Why does my code give an error of a Null Check Operator used on a null value - flutter

Here is the code
I wanted to register a user and I used a FormKey and I got the error Null
check operator use don a null value
here is what the run terminal shows
E/flutter (30851): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Null check operator used on a null value
E/flutter (30851): #0 _RegisterScreenState.signUp (package:em_home/screens/signing/register_screen.dart:58:29)
class RegisterScreen extends StatefulWidget {
const RegisterScreen({Key? key}) : super(key: key);
#override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
showSnackBar(String content, BuildContext context) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(content)));
}
bool _isLoading = false;
final formKey = GlobalKey<FormState>();
String email = "";
String password = "";
String fullName = "";
String dob = "";
String gender = "";
AuthMethods authMethods = AuthMethods();
Uint8List? image;
pickImage(ImageSource source) async {
final ImagePicker imagePicker = ImagePicker();
XFile? _file = await imagePicker.pickImage(source: source);
if (_file != null) {
return await _file.readAsBytes();
}
print("No Image selected");
}
void selectImage() async {
Uint8List im = await pickImage(ImageSource.gallery);
setState(() {
image = im;
});
}
signUp() async {
if (formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
await authMethods.registerUser(email: email, password: password, name: fullName, gender: gender, dateOfBirth: dob,)
.then((value) async {
if (value == true) {
await HelperFunctions.saveUserLoggedInStatus(true);
await HelperFunctions.saveUserEmailSF(email);
await HelperFunctions.saveUserNameSF(fullName);
Navigator.pushReplacement(context, SlideLeftRoute(widget: const LoginScreen()));
} else {
showSnackBar(value, context);
setState(() {
_isLoading = false;
});
}
});
}
return null;
}
void navigatetoSignIn() {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => const LoginScreen()));
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: backgroundColor,
body: SingleChildScrollView(
child: Container(
color: backgroundColor,
padding: const EdgeInsets.symmetric(horizontal: 15),
width: double.infinity,
child: Column(
children: [
const SizedBox(
height: 30,
),
Container(
alignment: Alignment.topLeft,
child: IconButton(
onPressed: () {
Navigator.pushReplacement(
context, SlideLeftRoute(widget: const LoginScreen()));
},
icon: const Icon(
Icons.arrow_back,
size: 40,
),
),
),
const SizedBox(
height: 20,
),
Image.asset(
'assets/logos.png',
),
const Text(
"Create your account",
style: TextStyle(color: textColor, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 30,
),
Stack(
children: [
// to check if Image is not equal to null
image != null
? CircleAvatar(
radius: 64,
backgroundImage: MemoryImage(image!),
)
: const CircleAvatar(
radius: 64,
backgroundImage: AssetImage(
"assets/default_profile.jpg",
),
),
Positioned(
child: IconButton(
onPressed: selectImage,
icon: const Icon(Icons.add_a_photo),
),
left: 80,
bottom: -10,
)
],
),
const SizedBox(
height: 30,
),
TextFormField(
decoration: textInputDecoration.copyWith(
labelText: "Email",
prefixIcon: Icon(
Icons.email,
)),
onChanged: (val) {
setState(() {
email = val;
});
},
// check tha validation
validator: (val) {
return RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val!)
? null
: "Please enter a valid email";
},
),
const SizedBox(
height: 20,
),
TextFormField(
obscureText: true,
decoration: textInputDecoration.copyWith(
labelText: "Password",
prefixIcon: Icon(
Icons.lock,
color: backgroundColor,
)),
validator: (val) {
if (val!.length < 6) {
return "Password must be at least 6 characters";
} else {
return null;
}
},
onChanged: (val) {
setState(() {
password = val;
});
},
),
const SizedBox(
height: 20,
),
TextFormField(
decoration: textInputDecoration.copyWith(
labelText: "Full Name",
prefixIcon: Icon(
Icons.person,
)),
onChanged: (val) {
setState(() {
fullName = val;
});
},
validator: (val) {
if (val!.isNotEmpty) {
return null;
} else {
return "Name cannot be empty";
}
},
),
const SizedBox(
height: 20,
),
TextFormField(
decoration: textInputDecoration.copyWith(
labelText: "Date Of Birth DD/MM/YYYY",
prefixIcon: Icon(
Icons.lock,
)),
validator: (val) {},
onChanged: (val) {
setState(() {
dob = val;
});
},
),
const SizedBox(
height: 20,
),
TextFormField(
decoration: textInputDecoration.copyWith(
labelText: "Gender",
prefixIcon: Icon(
Icons.lock,
)),
validator: (val) {},
onChanged: (val) {
setState(() {
gender = val;
});
},
),
const SizedBox(
height: 20,
),
InkWell(
onTap: signUp,
child: Container(
width: double.infinity,
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: const ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
color: buttonColor,
),
child: _isLoading
? const Center(
child: CircularProgressIndicator(
color: iconButtonColor,
),
)
: const Text(
"Sign up",
style: TextStyle(
color: buttonTextColor,
fontWeight: FontWeight.bold),
),
),
),
const SizedBox(
height: 50,
),
Container(
color: backgroundColor,
child: const Text("- or sign in using -"),
),
const SizedBox(
height: 25,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
Navigator.push(context, CustomRoute(widget: const Scaffold(body: Center(child: Text("Coming Soon"),))));
},
child: Container(
width: 50,
height: 45,
color: Colors.white,
child: Image.asset('assets/google.png'),
),
),
const SizedBox(
width: 30,
),
GestureDetector(
onTap: () {
Navigator.push(context, CustomRoute(widget: const Scaffold(body: Center(child: Text("Coming Soon"),))));
},
child: Container(
width: 50,
height: 45,
color: Colors.white,
child: Image.asset('assets/facebook.png'),
),
),
],
),
],
),
),
),
);
}
}
please what do I do here is the snippet to the code

Wrap your UI with the FormFields inside a Form widget and pass the GlobalKey to it.
Quick guide from Flutter docs: https://docs.flutter.dev/cookbook/forms/validation

Related

Flutter Textformfield error message shifted down the next widget

I have an issue with my textformfield. Whenever the error message shows, it shifted down the next widget below...
I try to search how to give a placement for the error text to no take a placement that does not exist when it is not shown, but I didn't find the solution.
Here are the screenshot and the code of the issue.
class AuthForm extends StatefulWidget {
final bool isPassword;
final IconData prefixIcon;
final String hintText;
late bool isPasswordVisible = isPassword;
final bool isCalendar;
final TextEditingController controller;
final bool isDropDown;
final bool isPhone;
final String? Function(String?)? validator;
AuthForm({Key? key, this.isPassword = false, required this.prefixIcon, required this.hintText,
this.isCalendar = false, required this.controller, this.isDropDown = false, this.isPhone = false, required this.validator}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
#override
void initState() {
super.initState();
if (widget.isPhone){
getCountryCode();
}
}
start () async {
await CountryCodes.init();
}
Locale? getCountryCode () {
start();
final Locale? deviceLocale = CountryCodes.getDeviceLocale();
final CountryDetails details = CountryCodes.detailsForLocale();
return deviceLocale;
}
DateTime selectedDate = DateTime(2000,1);
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
#override
Widget build(BuildContext context) {
return widget.isDropDown ? const DropDownBar() :
SizedBox(
width: 70.w,
child: TextFormField(
validator: widget.validator,
keyboardType: widget.isPhone ? TextInputType.phone : TextInputType.text,
inputFormatters: [DialCodeFormatter()],
controller: widget.controller,
textAlign: TextAlign.center,
obscureText: widget.isPasswordVisible,
style: Theme.of(context).textTheme.bodyText2,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 2.3.h, 0, 0),
hintText : widget.hintText,
hintStyle: Theme.of(context).textTheme.bodyText1,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).splashColor,
width: 0.13.w,
),
),
errorStyle: Theme.of(context).textTheme.headline6,
prefixIcon: Container(
width: 0,
alignment: const Alignment(-0.99, 0.5),
child: Icon(
widget.prefixIcon,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
suffixIcon: Visibility(
visible: widget.isPassword,
//Maintain the space where the widget is even if it is hid
maintainAnimation: true,
maintainState: true,
maintainSize: true,
child: InkWell(
highlightColor : Colors.transparent,
splashColor: Colors.transparent,
child: Container(
width: 0,
alignment: const Alignment(0.99, 0.5),
child: Icon(
widget.isPasswordVisible ? Icons.visibility : Icons.visibility_off,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
onTap: () {
setState(() {
widget.isPasswordVisible = !widget.isPasswordVisible;
});
},
),
),
),
onTap: () async {
if (widget.isCalendar){
//Dismiss the keyboard
FocusScope.of(context).requestFocus(FocusNode());
//Call the calendar
await _selectDate(context);
widget.controller.text = DateFormat('dd-MM-yyyy').format(selectedDate);
}
}
),
);
}
}
Login Page
#override
Widget build(BuildContext context) {
return BlocListener<InternetCubit, InternetState>(
listener: (context, state) {
if (state is InternetDisconnected) {
showAlertBox(context);
}
},
child: Form(
key: _formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 6.h,
),
Text(
"Flexmes",
style: Theme.of(context).textTheme.headline1,
),
SizedBox(
height: 8.h,
),
AuthForm(
prefixIcon: Icons.email_outlined,
hintText: "Email",
controller: emailController,
nextFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Email is required'),
EmailValidator(errorText: 'Enter a valid email address'),
]),
),
SizedBox(
height: 3.h,
),
AuthForm(
isPassword: true,
prefixIcon: Icons.lock_rounded,
hintText: "Password",
controller: passwordController,
currentFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Password is required'),
MinLengthValidator(6, errorText: 'Password must be at least 6 digits long'),
PatternValidator(r'(?=.*?[#?!#$%^&*-])', errorText: 'Passwords must have at least one special character')
]),
),
SizedBox(
height: 4.5.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomCheckbox(
iconColor: Colors.black,
activeColor: const Color.fromARGB(255, 3, 218, 197),
),
SizedBox(
width: 3.w,
),
Text(
"Remember me",
style: Theme.of(context).textTheme.bodyText2,
)
],
),
),
SizedBox(
height: 4.5.h,
),
AuthButton(
text: "Log In",
onPressed: (){
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
if (_formkey.currentState!.validate()){
AuthenticationAPI(auth: FirebaseAuth.instance).signInWithEmail(emailController.text, passwordController.text);
//return navigation
}
}
}
),
SizedBox(
height: 3.2.h,
),
ClickableText(
text: "Forgot Password ?",
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
//return navigation
}
},
),
SizedBox(
height: 3.2.h,
),
const AuthDivider(
text: "OR",
),
SizedBox(
height: 2.h,
),
SizedBox(
width: 70.w,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableImage(
imagePath: "assets/images/icon/Facebook.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Instagram.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Tiktok.png",
width: 23.w,
onPressed: () {
null;
},
),
],
),
),
SizedBox(
height: 4.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account ? ",
style: Theme.of(context).textTheme.bodyText2,
),
ClickableText(
text: 'Sign up Now !',
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
Navigator.of(context).pushNamed("/signup1");
}
},
),
],
),
),
],
),
),
);
}
}
Thanks for your suggestion,
Chris
try wrapping textformfield with container and giving it height and width
Try wrapping TextFormField with container and give it height and width.

Can't save the right image url on Firestore

Actually I am getting data by user, saving it in a map and adding this item to a list. When user has added all items in the list, it press the floating action button to add this list to an existing list on the firestore.
All data is being saved successfully except the imageUrl. First item in the list has null imageUrl at firestore however the second item is assigned the imageUrl of first Item. And the sequence goes on... I don't know what am I missing! I have subtracted most of code to be specific. I think the problem is being caused by the variable itemImageUrl that is being overridden. Help!
This is the code:
class RetrieveShop extends StatefulWidget {
String nameShop;String docId;
RetrieveShop(this.nameShop,this.docId);
#override
_RetrieveShopState createState() => _RetrieveShopState();
}
class _RetrieveShopState extends State<RetrieveShop> {
var result;
bool isLoading = false;
bool isLoadingNow = false;
var _price = TextEditingController();
var _itemName = TextEditingController();
/* var _id = TextEditingController();
var _category = TextEditingController();*/
var _desc = TextEditingController();
File _image;
File _image2;
String itemImageUrl;
bool _showDg = false;
bool condition = true;
bool isPopular = false;
bool savingAllDataToFirestore = false;
List itemo=[];
Future getImageFromGallery() async {
var image = await ImagePicker()
.getImage(source: ImageSource.gallery, imageQuality: 80);
setState(() {
_image = File(image.path);
print('Image Path $_image');
});
}
Future getImageFromCamera() async {
var image = await ImagePicker().getImage(source: ImageSource.camera);
setState(() {
_image = File(image.path);
print('Image Path $_image');
});
}
Future uploadItemOfShop(BuildContext context) async {
Reference ref = storage.ref().child(
"${this.widget.nameShop}'s ${_itemName.text} Price ${_price.text}" +
DateTime.now().toString());
if (_image.toString() == '') {
Flushbar(
title: "Menu Item Image is empty",
message: "Please Add some Image first",
backgroundColor: Colors.red,
boxShadows: [
BoxShadow(
color: Colors.red[800],
offset: Offset(0.0, 2.0),
blurRadius: 3.0,
)
],
duration: Duration(seconds: 3),
)
..show(context);
} else {
setState(() {
isLoadingNow=true;
});
debugPrint('wah');
UploadTask uploadTask = ref.putFile(_image);
uploadTask.then((res) async {
itemImageUrl = await res.ref.getDownloadURL();
}).then((value){
setState(() {
isLoadingNow=false;
});
debugPrint("Nullifing the Image object");
_image=_image2; //Trying to null the file object after it is used so thinking that might
//the problem is being caused here
});
}
}
Widget listTile(BuildContext context,String doc) {
return !isLoadingNow?SingleChildScrollView(
child: ListTile(
title: Wrap(
// mainAxisAlignment: MainAxisAlignment.start,
direction: Axis.horizontal,
children: [
Text(
"Enter details of Item",
style: TextStyle(fontSize: 22, color: Colors.black87),
),
Stack(
children: [
SizedBox(
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height / 2.5,
child: (_image != null)
? Image.file(
_image,
fit: BoxFit.cover,
)
: Image.network(
"https://images.unsplash.com/photo-1502164980785-f8aa41d53611?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
fit: BoxFit.fill,
),
),
Container(
alignment: Alignment.topLeft,
color: Colors.white38,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(
Icons.add_a_photo,
size: 30.0,
color: Colors.black,
),
onPressed: () {
getImageFromCamera();
},
),
SizedBox(
width: 10,
),
IconButton(
icon: Icon(
Icons.create_new_folder_rounded,
size: 30.0,
color: Colors.black,
),
onPressed: () {
getImageFromGallery();
},
),
],
),
)
],
),
],
),
subtitle: Column(
children: [
TextField(
controller: _itemName,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Enter Item name',
icon: Icon(Icons.fastfood),
alignLabelWithHint: true,
hintText: "Zinger Burger etc"),
autofocus: true,
),
TextField(
controller: _price,
autofocus: false,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Enter Price',
icon: Icon(Icons.attach_money),
alignLabelWithHint: true,
hintText: "70 etc"),
),
SwitchListTile(
title: condition ? Text("Fresh") : Text("Used"),
value: condition,
onChanged: _onConditionChanged,
),
SwitchListTile(
title: isPopular ? Text("Popular") : Text("Not Popular"),
value: isPopular,
onChanged: _onPopularityChanged,
),
TextField(
autofocus: false,
maxLength: 150,
controller: _desc,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: InputDecoration(
labelText: 'Enter Description',
icon: Icon(Icons.description),
alignLabelWithHint: true,
hintText:
"This item contains cheez and paneer with delicious mayonees etc.."),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
child: Text(
"Save",
style: TextStyle(color: Colors.white, fontSize: 16),
),
color: Colors.red,
onPressed: () {
if(_image !=null){
int price=int.parse(_price.text);
String itemName=_itemName.text;
String itemDesc=_desc.text;
String categoryO=this.categoryToSave;
String imageUrl=this.itemImageUrl;
uploadItemOfShop(context).then((value){
String idO=getRandomString(3);
var item = {
'itemName': itemName,
'itemPrice': price,
'itemDesc': itemDesc,
'category': categoryO,
'condition': condition,
'imageUrl': imageUrl,
'isPopular': this.isPopular,
'id': idO,
};
setState(() {
itemo.add(item);
});
});
setState(() {
_showDg = false;
});
_price.clear();
_desc.clear();
_itemName.clear();
/* imageUrl='';
itemImageUrl='';*/
}else{
Fluttertoast.showToast(msg: 'Please select some image first');
}
}
),
],
),
],
),
selectedTileColor: Colors.red.shade300,
),
):Padding(
padding: const EdgeInsets.all(40.0),
child: Center(
child:CircularProgressIndicator()
),
);
}
Widget myList(String nameOfButton2, {BuildContext buildContext}) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
StreamBuilder(
stream: FirebaseFirestore.instance.collection('shops').where(
'name', isEqualTo: this.widget.nameShop).snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.hasData){
DocumentSnapshot list=snapshot.data.docs.single;
return isLoadingNow
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: list.data()['menu'].length,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context,int index){
return Card(
shadowColor: Colors.red,
//color: Colors.black,
elevation: 8.0,
//borderOnForeground: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
margin: EdgeInsets.only(
bottom: 10, right: 10),
child: ListTile(
leading: CachedNetworkImage(
fit: BoxFit.cover,
//height: 100,
placeholderFadeInDuration:
Duration(seconds: 2),
fadeOutDuration: Duration(seconds: 2),
imageUrl: list
.data()['menu'][index]['imageUrl'],
progressIndicatorBuilder: (context, url,
downloadProgress) =>
Center(
child:
CircularProgressIndicator(
value: downloadProgress.progress,
color: kPrimaryColor,
)),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
title:Text('Name: ${list.data()['menu'][index]['itemName']}'),
subtitle: Column(
crossAxisAlignment:CrossAxisAlignment.start,
children:[
Text(
"Price: ${list.data()['menu'][index]['itemPrice']} Rs",
style: TextStyle(
color: Colors.black54,
fontSize: 18),
),
Text(
"Description: ${list.data()['menu'][index]['itemDesc']}",
style: TextStyle(
color: Colors.black87, fontSize: 20),
),
list.data()['menu'][index]['condition']
? Text("Condition: Fresh")
: Text("Condition: Used"),
]
),
),
);
},
);
}
if(snapshot.hasError){
return Text('Please try again');
}
return Center(
child: CircularProgressIndicator(),
);
},
),
]
,
);
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("${this.widget.nameShop}"),
centerTitle: false,
actions: [
IconButton(
icon: Icon(Icons.add_comment),
onPressed: () {
setState(() {
_showDg = !_showDg;
});
})
],
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
_showDg ? listTile(context,this.widget.docId) : Text(""),
myList(this.widget.nameShop),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: Text("Items ${itemo.length.toString()}"),
onPressed: (){
if(itemo.length==0){
Fluttertoast.showToast(msg: 'Please add some items first');
}else{
FirebaseFirestore.instance.collection('shops').doc(this.widget.docId).update({
"menu": FieldValue.arrayUnion(itemo),
});
setState(() {
itemo=[];
});
}
},
),
);
}
}
Was just missing await before the object of uploadtask.

When routing to another page I get "There are multiple heroes that share the same tag within a subtree"

I am trying to navigate from one screen to another with route. When I hit the button for the page to move to the route provided I get the error:
I/flutter ( 8790): Another exception was thrown: There are multiple heroes that share the same tag within a subtree.
Sharing with you the source code:
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_counter/flutter_counter.dart';
import 'package:gender_selection/gender_selection.dart';
import 'package:group_chats/addContactUI.dart';
import 'package:group_chats/addPhone.dart';
import 'package:group_chats/letGoUI.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Animation/FadeAnimation.dart';
import 'Model/insertUserModel.dart';
class AddProfileUI extends StatefulWidget {
final List<String> listFriends;
final String phone;
AddProfileUI(this.listFriends, this.phone);
#override
_AddProfileUIState createState() => _AddProfileUIState();
}
class _AddProfileUIState extends State<AddProfileUI> {
File _image;
final picker = ImagePicker();
final _formKey = GlobalKey<FormState>();
String name = "";
String city = "";
TextEditingController dobController = TextEditingController();
bool single = false;
Gender gender;
final _scaffoldKey = GlobalKey<ScaffoldState>();
int defaultValue = 18;
List<String> selectedContact;
SharedPreferences prefs;
bool _loading = true;
Future initPrefs() async {
prefs = await SharedPreferences.getInstance();
}
uploadImage(String userId) async {
try {
FormData formData = new FormData.fromMap({
"file":
await MultipartFile.fromFile(_image.path, filename: "$userId.jpg"),
});
var response = await Dio().post(
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/upload_profile/$userId",
data: formData);
if (response.statusCode == 200)
return response.data;
else
return null;
} catch (e) {
print(e.toString());
return null;
}
}
Future<InsertUserModel> insertData() async {
try {
for (int i = 0; i < selectedContact.length; i++) {
if (selectedContact[i][0] == "0") {
selectedContact[i] = selectedContact[i].replaceRange(0, 1, "+972");
}
}
var body = jsonEncode({
"gender": gender.index == 0 ? "male" : "female",
"city": city,
"last_login": {},
"friends": selectedContact ?? [],
"single": single,
"name": name,
"phone_number": widget.phone,
"age": defaultValue
});
final String apiUrl =
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/users/${AddPhoneUI.uid}";
final response = await http.post(apiUrl,
headers: {"content-type": "application/json"}, body: body);
if (response.statusCode == 200) {
final responseString = response.body;
return insertUserModelFromJson(responseString);
}
} catch (e) {
setState(() {
_loading = false;
});
}
}
getUserData() async {
try {
final String apiUrl =
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/users/";
final response = await http.get(apiUrl);
if (response.statusCode == 200) {
final responseString = response.body;
return insertUserModelFromJson(responseString);
}
} catch (e) {
setState(() {
_loading = false;
});
Scaffold.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.red,
content: Text('Error: ${e.toString()}'),
duration: Duration(milliseconds: 2500),
));
}
}
Future<void> _selectStartingDate(BuildContext context) async {
DateTime selectedDate = DateTime.now();
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950),
lastDate: DateTime(
DateTime.now().year, DateTime.now().month, DateTime.now().day),
);
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
dobController.text = selectedDate.year.toString() +
"-" +
selectedDate.month.toString() +
"-" +
selectedDate.day.toString();
});
}
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
showPopUp(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape:
OutlineInputBorder(borderRadius: BorderRadius.circular(14.0)),
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 20.0,
),
Text(
"My Profile",
style: TextStyle(
fontSize: 27.0, fontWeight: FontWeight.w600),
),
SizedBox(
height: 30.0,
),
RichText(
text: TextSpan(
text: "Your friends will be able to\nsee ",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
children: <TextSpan>[
TextSpan(
text: 'only',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500)),
TextSpan(text: 'your picture and\name.'),
],
)),
SizedBox(
height: 10.0,
),
RichText(
text: TextSpan(
text: "Other fields are used for\n",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
children: <TextSpan>[
TextSpan(
text: 'research issues',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500)),
TextSpan(text: "only."),
],
)),
SizedBox(
height: 10.0,
),
RichText(
text: TextSpan(
text: "Please fill all the fields.",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
)),
SizedBox(
height: 80.0,
),
MaterialButton(
shape: OutlineInputBorder(
borderSide: BorderSide(width: 1.0)),
color: Colors.white38,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: Text(
"Ok, got it",
style: TextStyle(fontSize: 18.0),
),
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
));
}
#override
void initState() {
super.initState();
selectedContact = widget.listFriends;
initPrefs();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {},
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddContactUI(),
)).then((value) {
setState(() {
selectedContact = value;
});
});
},
child: Column(
children: [
Icon(
Icons.supervisor_account,
size: 40.0,
),
Text("Add Friends"),
],
),
)
],
),
),
Container(
child: GestureDetector(
onTap: () async {
await getImage();
},
child: CircleAvatar(
radius: 60.0,
backgroundImage: _image != null
? Image.file(_image).image
: Image.asset("assets/empty.png").image,
backgroundColor: Colors.transparent,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: FadeAnimation(
1.7,
Form(
key: _formKey,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Color(0xff5E17EB).withOpacity(0.3),
blurRadius: 20,
offset: Offset(0, 10),
)
]),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey[200]))),
child: TextFormField(
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) =>
FocusScope.of(context).nextFocus(),
onChanged: (val) {
setState(() {
name = val;
});
},
validator: (val) =>
val.isEmpty ? "Enter Name" : null,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Name",
hintStyle: TextStyle(color: Colors.grey)),
),
),
Container(
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey[200]))),
padding: EdgeInsets.all(10),
child: TextFormField(
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
onChanged: (val) {
setState(() {
city = val;
});
},
validator: (val) {
if (val.isEmpty) return "Enter City";
// if (val.length < 6)
// return "Password should be at least 6 characters";
return null;
},
decoration: InputDecoration(
border: InputBorder.none,
hintText: "City",
hintStyle: TextStyle(color: Colors.grey)),
),
),
Container(
height: 140.0,
padding: EdgeInsets.all(10),
child: GenderSelection(
selectedGender: gender,
maleText: "", //default Male
femaleText: "", //default Female
linearGradient: LinearGradient(colors: [
Colors.indigo,
Colors.black
]), //List: [Colors.indigo, Colors.black]
selectedGenderIconBackgroundColor:
Colors.indigo, // default red
checkIconAlignment:
Alignment.centerRight, // default bottomRight
selectedGenderCheckIcon:
null, // default Icons.check
onChanged: (Gender gender) {
this.gender = gender;
print(this.gender);
},
equallyAligned: true,
animationDuration: Duration(milliseconds: 400),
isCircular: true, // default : true,
isSelectedGenderIconCircular: true,
opacityOfGradient: 0.6,
padding: const EdgeInsets.all(3),
size: 120, //default : 120
),
),
SizedBox(
height: 10.0,
),
Row(
children: [
Checkbox(
value: single,
onChanged: (value) {
setState(() {
single = !single;
});
},
),
Text(
"Are you Single?",
style: TextStyle(fontSize: 16.0),
)
],
),
Padding(
padding: const EdgeInsets.all(14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
"Age:",
style: TextStyle(fontSize: 18.0),
),
Counter(
initialValue: defaultValue,
buttonSize: 35.0,
textStyle: TextStyle(fontSize: 25.0),
minValue: 0,
color: Colors.black,
maxValue: 80,
step: 1,
decimalPlaces: 0,
onChanged: (value) {
// get the latest value from here
setState(() {
defaultValue = value;
});
},
),
],
),
),
],
),
),
),
),
),
SizedBox(
height: 20.0,
),
FadeAnimation(
1.9,
MaterialButton(
shape: OutlineInputBorder(borderSide: BorderSide(width: 1.0)),
color: Colors.black,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: Text(
"Next",
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
InsertUserModel result = await insertData();
// var imageResult = await uploadImage(result.id);
print(result.data[0].id);
if (_image != null) {
await uploadImage(result.data[0].id);
}
setState(() {
_loading = false;
});
if (result != null) {
await prefs.setString("userID", result.data[0].id);
final snackBar = SnackBar(
content: Text(
result.message,
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green,
duration: Duration(milliseconds: 2000),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LetGoUI(result.data[0].id),
));
} else {
final snackBar = SnackBar(
content: Text(
"Here is some error, please try again later!",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.red,
duration: Duration(milliseconds: 2000),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
}
},
),
)
],
),
),
),
);
}
}
I really don't understand what is the problem because I'm not using any Heros and not have double FloatingActionButton.
How do I solve this?
Thanks
There might be problem with showing snackbar while navigating. you should remove that problem by calling following method before navigating.
void removeSnackBarCallsBeforeNavigation() {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
}

Flutter: form shifts when validation is false

i'm building a UI for a login form with validation.
Here is the page:
I'm overall very pleased with the look of the page and it works fine. There is just one exception: when the user inputs invalid parameters in the fields (one or more) the form shifts and the button responsable for the password visibility is not centered anymore.
I searched online and they suggest to wrap it in an Expanded widget, but it doesn't solve my problem.
Here's a image, that shows the problem:
Here is the code:
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:client/providers/cloudfirestore_provider.dart';
import 'package:client/screens/forgotpass_screen.dart';
import 'package:client/screens/register_screen.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
FirebaseAuth auth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
final email = TextEditingController();
final password = TextEditingController();
bool _obscureText = true;
IconData iconData = Icons.visibility;
var isLoading = false;
final focus = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (ctx) => SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.yellow,
width: double.infinity,
height: MediaQuery.of(context).padding.top,
),
Stack(
alignment: Alignment.center,
children: [
Container(
color: Colors.yellow,
width: double.infinity,
height: (MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top) *
0.4,
),
ClipRRect(
borderRadius: BorderRadius.circular(100.0),
child: Container(
child: Image.asset('assets/images/logo.jpg'),
height: 150,
width: 150,
),
),
],
),
Container(
height: (MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top) *
0.6,
padding: EdgeInsets.symmetric(vertical: 30, horizontal: 60),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Hi, there!",
style: TextStyle(fontSize: 20, color: Colors.grey[900]),
),
Container(
height: 210,
child: Form(
key: _formKey,
child: Column(
children: [
Expanded(
child: TextFormField(
textInputAction: TextInputAction.next,
onFieldSubmitted: (v) {
FocusScope.of(context).requestFocus(focus);
},
controller: email,
decoration: InputDecoration(labelText: "Email"),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (EmailValidator.validate(value)) {
return null;
}
return "Please enter a valid email";
},
),
),
Expanded(
child: Stack(
children: [
TextFormField(
focusNode: focus,
controller: password,
decoration:
InputDecoration(labelText: "Password"),
obscureText:
_obscureText, // create little eye to show password
validator: (value) {
if (value.length < 6) {
return 'Minimum 6 characters';
}
return null;
},
),
IconButton(
icon: Icon(iconData),
onPressed: () {
setState(
() {
_obscureText = !_obscureText;
if (iconData == Icons.visibility) {
iconData = Icons.visibility_off;
} else {
iconData = Icons.visibility;
}
},
);
})
],
alignment: Alignment.bottomRight,
),
),
SizedBox(
height: 20,
),
Container(
width: 200,
height: 50,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
color: Colors.deepOrange,
textColor: Colors.white,
onPressed: () async {
Scaffold.of(ctx).hideCurrentSnackBar();
setState(() {
isLoading = true;
});
if (_formKey.currentState.validate()) {
login(email, password) async {
try {
await FirebaseAuth.instance.signOut();
await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: email.text,
password: password.text);
if (FirebaseAuth.instance.currentUser
.emailVerified ==
false)
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(
"Please verify your email."),
),
);
else
Scaffold.of(ctx).showSnackBar(
SnackBar(
content:
Text("Logging you in ..."),
),
);
setState(() {
isLoading = false;
});
} catch (e) {
print(e.toString());
if (e.toString() ==
"[firebase_auth/wrong-password] The password is invalid or the user does not have a password.") {
Scaffold.of(ctx)
.hideCurrentSnackBar();
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(
"The password is incorrect."),
),
);
} else if (e.toString() ==
"[firebase_auth/user-not-found] There is no user record corresponding to this identifier. The user may have been deleted.") {
Scaffold.of(ctx)
.hideCurrentSnackBar();
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(
"There is no email adress connected to this account."),
),
);
} else if (e.toString() ==
"[firebase_auth/too-many-requests] We have blocked all requests from this device due to unusual activity. Try again later.") {
Scaffold.of(ctx)
.hideCurrentSnackBar();
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(
"We have blocked all requests from this device due to unusual activity. Try again later."),
),
);
} else {
Scaffold.of(ctx)
.hideCurrentSnackBar();
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(
"Pls check your internet connection and try again."),
),
);
}
setState(() {
isLoading = false;
});
}
}
await login(email, password).whenComplete(
() => CloudFirestoreProvider().addUser(
email.text,
password.text,
));
} else
setState(() {
isLoading = false;
});
},
child: (isLoading)
? CircularProgressIndicator(
backgroundColor: Colors.white,
)
: Text('Submit',
style: TextStyle(fontSize: 22)),
),
),
],
),
),
),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: Row(
children: [
FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ForgotPassScreen(),
),
);
},
child: Text(
"Forgot Password ?",
style: TextStyle(color: Colors.deepOrange),
),
),
Expanded(child: SizedBox()),
FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegisterScreen(),
),
);
},
child: Text(
"Register",
style: TextStyle(color: Colors.deepOrange),
),
),
],
),
),
)
],
),
),
],
),
),
),
);
}
}
EDIT:
I tried swapping the Stack method for the suffixIcon suggested. And it works except for the position of the Icon that is off-centred.
Here's the updated code:
Expanded(
child: TextFormField(
focusNode: focus,
controller: password,
decoration: InputDecoration(
labelText: "Password",
suffixIcon: IconButton(
color: Colors.grey[900],
icon: Icon(iconData),
onPressed: () {
setState(
() {
_obscureText = !_obscureText;
if (iconData ==
Icons.visibility) {
iconData = Icons.visibility_off;
} else {
iconData = Icons.visibility;
}
},
);
})),
obscureText:
_obscureText, // create little eye to show password
validator: (value) {
if (value.length < 6) {
return 'Minimum 6 characters';
}
return null;
},
),
),
Put your icon in the sufficient property of the input Decoration on your password text field.
inputDecoration(suffixIcon: IconButton())

How to validate a form in Flutter

I am trying to validate my fields before submitting in flutter. But somehow it doesn't validate as the validate always comes true even if the fields are empty.
This is what I tried. Can someone help me to identify what I have done wrong?
as you can see below, I have even set the validators and controller. But still the Submission happens even when the fields are empty
class _AddNewsState extends State<AddNews> {
GlobalKey<FormState> _key = GlobalKey<FormState>();
TextEditingController _headlineController;
TextEditingController _descriptionController;
String _dropDownActivity;
// get current date
static var now = new DateTime.now();
static var formatter = new DateFormat('yyyy-MM-dd');
String formattedDate = formatter.format(now);
// get current timie
dynamic currentTime = DateFormat.jm().format(DateTime.now());
#override
void initState() {
super.initState();
_headlineController = TextEditingController();
_descriptionController = TextEditingController();
_dropDownActivity = "";
}
#override
Widget build(BuildContext context) {
File _image;
String image_url = "";
FileImage _getImage() {
var img = (File(widget.imgPath));
setState(() {
_image = img;
});
return FileImage(_image);
}
Future _showToastMsg(String msgType, String msg) {
if (msgType == "success") {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.green,
);
} else if (msgType == "error") {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.red,
);
} else {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.black,
);
}
}
get_image_url_from_uploadPicture(String url) {
image_url = url;
return image_url;
}
showLoadingWhileSaving(BuildContext context) {
AlertDialog alert = AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(margin: EdgeInsets.only(left: 5), child: Text("Loading")),
],
),
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Future _uploadPicture(BuildContext context) async {
String fileName = basename(_image.path);
StorageReference storageReference =
FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask storageUploadTask = storageReference.putFile(_image);
showLoadingWhileSaving(context);
StorageTaskSnapshot storageTaskSnapshot =
await storageUploadTask.onComplete;
image_url =
await (await storageUploadTask.onComplete).ref.getDownloadURL();
get_image_url_from_uploadPicture(image_url);
Navigator.pop(context);
setState(() {
_showToastMsg("success", "News Successfully Saved!");
});
}
return Scaffold(
appBar: AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(null),
color: Colors.white,
onPressed: () {},
);
},
),
centerTitle: true,
title: Text(
"Report a News",
),
backgroundColor: Colors.blueGrey,
),
body: Container(
child: SingleChildScrollView(
padding: const EdgeInsets.all(26.0),
child: Form(
key: _key,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.center,
child: GFImageOverlay(
border: Border.all(color: Colors.blueGrey, width: 4.0),
height: 200,
width: 200,
color: Colors.red,
shape: BoxShape.circle,
boxFit: BoxFit.fill,
image: (widget.imgPath != null)
? _getImage()
: AssetImage("images/default_news_image.png"),
)),
SizedBox(
height: 30.0,
),
TextFormField(
textInputAction: TextInputAction.next,
controller: _headlineController,
validator: (headline) {
if (headline == null || headline.isEmpty) {
_showToastMsg("error", "Please enter a Headline");
}
},
decoration: InputDecoration(
labelText: "Headline",
hintText: "Covid-19 new stats",
border: OutlineInputBorder(),
icon: Icon(Icons.add_box),
),
),
SizedBox(
height: 16.0,
),
TextFormField(
maxLines: 5,
textInputAction: TextInputAction.next,
controller: _descriptionController,
validator: (description) {
if (description == null || description.isEmpty) {
_showToastMsg("error", "Please provide a Headline");
}
},
decoration: InputDecoration(
labelText: "Description",
hintText: "Covid-19 new stats are sky-rock...",
border: OutlineInputBorder(),
icon: Icon(Icons.message),
),
),
SizedBox(
height: 16.0,
),
DropDownFormField(
titleText: 'Priority',
value: _dropDownActivity,
hintText: 'Select the priority',
onSaved: (value) {
setState(() {
_dropDownActivity = value;
});
},
onChanged: (value) {
setState(() {
_dropDownActivity = value;
});
},
validator: (value) {
if (value == null || value == "") {
_showToastMsg("error", "Please select a priority");
}
},
dataSource: [
{
"display": "High",
"value": "High",
},
{
"display": "Medium",
"value": "Medium",
},
{
"display": "Low",
"value": "Low",
},
],
textField: 'display',
valueField: 'value',
),
SizedBox(
height: 16.0,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
GFButtonBadge(
size: GFSize.SMALL,
onPressed: () {
_showToastMsg(
"other", "Today is : ${formattedDate}");
},
icon: Icon(
Icons.calendar_today,
size: 16.0,
color: Colors.white,
),
text: '',
),
SizedBox(
width: 10.0,
),
Text(
"- ${formattedDate}",
style: TextStyle(fontSize: 18.0),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: <Widget>[
GFButtonBadge(
size: GFSize.SMALL,
onPressed: () {
_showToastMsg("other", "Time is : ${currentTime}");
},
icon: Icon(
Icons.alarm,
size: 16.0,
color: Colors.white,
),
text: '',
),
SizedBox(
width: 10.0,
),
Text(
"- ${currentTime}",
style: TextStyle(fontSize: 18.0),
),
],
),
SizedBox(
height: 14.0,
),
],
),
Align(
alignment: Alignment.center,
child: Text(
"Date and time will be saved automaticallt on \"Save\"",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
),
),
),
SizedBox(
height: 20.0,
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton.icon(
icon: Icon(Icons.refresh),
color: Colors.orange,
textColor: Colors.white,
label: Text("Retake"),
onPressed: () async {
Navigator.of(context).pop();
},
),
RaisedButton.icon(
icon: Icon(Icons.add_a_photo),
color: Colors.green,
textColor: Colors.white,
label: Text("Snap"),
onPressed: () async {
try {
// first upload the photo
if (_key.currentState.validate()) {
_showToastMsg("other",
get_image_url_from_uploadPicture("cool"));
} else {
_showToastMsg("other",
get_image_url_from_uploadPicture("empty"));
}
// await FireStoreServiceApi().add_news(News(
// headline: _headlineController.text,
// description: _descriptionController.text,
// imageUrl: image_url,
// timeNews: currentTime.toString(),
// timeDate: formattedDate.toString(),
// priority: _dropDownActivity.toString(),
// ));
} catch (e) {
print(e);
}
},
),
],
),
],
),
),
),
),
);
}
}
Tell me where I have gone wrong and how to fix that
Thank you.
You must return a String in the validator whenever you want to show an input error.
TextFormField(
textInputAction: TextInputAction.next,
controller: _headlineController,
validator: (headline) {
if (headline == null || headline.isEmpty) {
return "Please enter a Headline";
}
return null;
},
decoration: InputDecoration(
labelText: "Headline",
hintText: "Covid-19 new stats",
border: OutlineInputBorder(),
icon: Icon(Icons.add_box),
),
),