FutureBuilder not working in OnTap() of GestureDetector - flutter

Upon user registration, I wish to call my database at Firebase to check that the email is unique. If it is not, I wish to show some form of an error message to the user.
However, for some reason the build method of my FutureBuilder is not called at all and none of my widgets in the submit() function are shown:
final usersRef = Firestore.instance.collection("users");
class _CreateAccountWithEmailState extends State<CreateAccountWithEmail> {
Future<QuerySnapshot> existingUserWithEmail;
emailExists(String email) {
Future<QuerySnapshot> existingUserWithEmailFromDb =
usersRef.where("email", isEqualTo: email).getDocuments();
setState(() {
existingUserWithEmail = existingUserWithEmailFromDb;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: header(context, titleText: "Complete your profile"),
body: ListView(children: [
....
Padding(
padding: EdgeInsets.only(top: topPadding),
child: Center(
child: GestureDetector(
onTap: () =>
{submit(context, context.read<UserSignupForm>().email)},
child: Container(
height: 50.0,
width: 350.0,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(7.0)),
child: Center(
child: Text(
"Save",
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold),
))),
),
),
)
]));
}
Widget submit(BuildContext context, String email) {
return FutureBuilder(
future: emailExists(email),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: Text('Please wait its loading...'));
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return Center(
child: new Text(
'Test: ${snapshot.data}'));
}
});
}
}
Via debugging, I found that the future in the FutureBuilder is called, but not the builder. Any ideas please?

Okay, so basically calling submit function which returns FutureBuilder actually makes no sense because it has a return type of Widget.
I don't actually quite fully know what you are wanting to accomplish here.
But here's one solution to show the user if the user exists with the email already.
final usersRef = Firestore.instance.collection("users");
class _CreateAccountWithEmailState extends State<CreateAccountWithEmail> {
bool? userExistsAlready;
bool isBusy = false;
Future<void> emailExists(String email) {
setState(() {
isBusy = true;
});
final getDocs = await usersRef.where("email", isEqualTo: email).get();
setState(() {
userExistsAlready = getDocs.docs.isNotEmpty;
isBusy = false;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: header(context, titleText: "Complete your profile"),
body: ListView(children: [
....
Padding(
padding: EdgeInsets.only(top: topPadding),
child: Center(
child: isBusy
? CircularProgressIndicator()
: GestureDetector(
onTap: ()
=> emailExists(context.read<UserSignupForm>().email),
child: Container(
height: 50.0,
width: 350.0,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(7.0)),
child: Center(
child: Text(
"Save",
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold),
),
)
),
),
),
),
userExistsAlready == null ? SizedBox.shrink() :
Text('User Exists Already: ${userExistsAlready}')
],
),
);
}

Related

Update Appbar after stream builder is done

After stream builder is done, it has the numitems as number of valid items. This numitems should show on a cart icon in AppBar. Right now the it is showing no number on cart icon as the UI is built before the stream builder is fully done.
The stream builder is inside the body widget as it also displays a list of items on the screen. Thats why I dont prefer to havestream builder within AppBar. I was wondering what is the suitable way to update AppBar with numitems after stream builder is finished.
Here is the code:
class BasketPage extends StatefulWidget {
String title;
UserAccount useraccount;
BasketPage({required this.title, required this.useraccount});
#override
BasketPageState createState() {
return BasketPageState(title: this.title, useraccount: this.useraccount);
}
}
class BasketPageState extends State<BasketPage> {
int numitems = 0;
Stream<QuerySnapshot>? fooditemsStream;
CollectionReference? fooditems;
BasketPageState(){
this.fooditems = FirebaseFirestore.instance.collection('fooditems');
this.fooditemsStream = this.fooditems!
.where("receiever", isEqualTo: this.useraccount.uname)
.where("taken", isNull: true)
.snapshots();
}
BasketBloc? basketBloc;
List<FoodItem> foodItemsList = [];
#override
Widget build(BuildContext context) {
basketBloc = BlocProvider.of<BasketBloc>(context);
return Scaffold(
appBar: AppBar(
actions: [
Stack(
children: <Widget>[
const IconButton(
icon: Icon(
Icons.shopping_cart_sharp,
color: Colors.white,
),
onPressed: null,
),
this.numitems==0 // if numitems is 0 then return empty container else display numitems value
? Container()
: Positioned(
top: 0,
right: 0,
child: Stack(
children: <Widget>[
Container(
height: 20.0,
width: 20.0,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: const Center(
child: Text(
"10",
style: TextStyle(
color: Colors.white,
fontSize: 11.0,
fontWeight: FontWeight.bold,
),),),),],),),],),],),
body: SingleChildScrollView(
child: SafeArea(
child: Column(
children: <Widget>[
BlocListener<BasketBloc,BasketState>(
listener: (context,state){},
child: BlocBuilder<BasketBloc,BasketState>(
builder: (context,state) {
return Container();
}),),
Flexible(
child:
Column(
children: [
SizedBox(
child: StreamBuilder<QuerySnapshot>(
stream: fooditemsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if (snapshot.data!.docs.length == 0){
return Text("Currently there are no food items in the list");
}
// else return list and update numitems when building list
return Column(
children: [
ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
final bool isExpired = data['expired'];
if (isExpired) return Container();
// update numitems here
numitems= numitems+1;
return ListTile(
contentPadding:const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0, bottom:5.0),
title: Padding(
padding: const EdgeInsets.only(bottom:8.0),
child: Text(capitalize(data['item_name']),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
),
);
}).toList(),
),],);},),),],)),],),),);}}
Thanks!
The easiest solution is just to add setState() after you update numitems = numitems + 1. This will make your whole BasketPage to rebuild.
But it's not the best solution, because your it causes your whole page to rebuild, when it is unnecessary. Better solution would be to use ValueNotifier. Wrap your AppBar with ValueListenableBuilder and create ValueNotifier.
As a side note you don't need to pass anything to your BasketPageState. If you need to access them use widget.title

Type 'Future<dynamic>' is not subtype of type 'Widget'

I am showing markers from API on google maps. Here is my build method. When the program reaches the _widgetbuilder() method, it throws the specific error of type Future is not a subtype of the widget. If someone could please help to solve the problem and also tell me that what exactly this error means.....
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: FutureBuilder<List<MarkersOnMap>>(
future: future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData)
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
if (snapshot.hasData && snapshot.data.isEmpty) {
return Center(
child: Container(
child: Column(
children: [
Text(
'No Properties Added Yet\nPlease Add Some!',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
PageTransition(
duration: Duration(microseconds: 500),
type: PageTransitionType.fade,
child: AddNewEproperty(
createEproperty: widget.createEproperty),
),
);
},
label: Text('Add'),
icon: Icon(Icons.add),
),
],
),
),
);
} else
_widgetbuilder();
if (snapshot.hasData) {
return ListView.builder(
itemCount: allWidgets.length + 1,
shrinkWrap: true,
padding: EdgeInsets.only(top: 16),
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, i) {
return Stack(
children: <Widget>[
Container(),],);},);},},),);}
This is the _widgetbuilder() method. When it reaches this return _widgetbuilder, throws _typeerror.
_widgetbuilder() async {
allWidgets = [];
widget.markersonmap = await future;
widget.markersonmap.forEach(
(element) {
print(element);
allWidgets.add(
Container(
height: 25,
width: 50,
child: new DecoratedBox(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(5.0),
color: Colors.black54),
child: Text(
element.ePropertiesCardsList.price.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
);
},
);
}
You are getting this error because your function _widgetbuilder returns Future<dynamic> because the function is async.
Widget _widgetbuilder(){
// code here
}
The function should be in this structure to return of type Widget. The code that needs to be async should either be taken out of build function or use .then pattern for async code instead of async await if you really need to.
This short 9 min video will help you understand async better in flutter.
In here now the type error is solved but after reading 'future.then..... it does not goto the future and fetch data but jumps to the next foreach line and then calls it as null.
_widgetbuilder() {
allWidgets = [];
// widget.markersonmap = await future;
future.then((value) {
widget.markersonmap = value;
});
widget.markersonmap.forEach(
(element) {
print(element);
allWidgets.add(
Container(
// other code
}

The element type 'Future<Widget>' can't be assigned to the list type 'Widget'

I tried couple of solutions given but nothing worked for me
//this basically lays out the structure of the screen
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.only(
top: 30,
bottom: 60,
),
child: Column(
children: [
buildTitle(),
SizedBox(
height: 50,
),
buildForm(),
Spacer(),
buildBottom(),
],
),
),
);
}
//problem is with buildForm
Future<Widget> buildForm() async {
final valid = await usernameCheck(this.username);
return Container(
width: 330,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Form(
key: _userNameformKey,
child: TextFormField(
textAlign: TextAlign.center,
onChanged: (value) {
_userNameformKey.currentState.validate();
},
validator: (value) {
if (value.isEmpty ) {
setState(() {
onNextButtonClick = null;
});
}
else if(!valid){
setState(() {
//user.user.username=value;
onNextButtonClick = null;
showDialog(
context: context,
builder: (context) =>
new AlertDialog(
title: new Text('Status'),
content: Text(
'Username already taken'),
actions: <Widget>[
new ElevatedButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(); // dismisses only the dialog and returns nothing
},
child: new Text('OK'),
),
],
),
);
Try using FutureBuilder<T>
Widget build(_) {
return FutureBuilder<bool>(
future: usernameCheck(this.username),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if(!snapshot.hasData) { // not loaded
return const CircularProgressIndicator();
} else if(snapshot.hasError) { // some error
return const ErrorWidget(); // create this class
} else { // loaded
bool valid = snapshot.data;
return Container(/*...details omitted for conciseness...*/);
}
}
)
}

Cloud firestore documentation for flutter

I am trying to write an app with flutter using cloud firestore but in the examples page I do not see a flutter/dart option for the example code, am I missing something?
Here is where I am looking at https://firebase.google.com/docs/firestore/query-data/get-data
Any help would be great. Thanks
There are indeed no examples for Flutter in the Firebase documentation. What I do is that I read the Firebase documentation on the topic I'm trying to learn more about, and then use the FlutterFire documentation for Firestore to construct the corresponding Flutter example myself.
To navigate to the Flutter example, but step-wise it (currently) is:
Go to the home page of the cloud_firestore plugin.
Click on the Example tab
I also frequently use the FlutterFire reference documentation for Firestore to look up API signatures for Flutter, based on the examples in the Firebase documentation for Firestore.
Sorry for late answer,
I was resolving my own project issue.
By the way I have Implemented CRUD Operation with cloud_firestore plugin.
SEE_CRUD_OPREATION_OUTPUT_VIDEO
Here you can analyse my
full code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class CRUDoperation extends StatefulWidget {
#override
_CRUDoperationState createState() => _CRUDoperationState();
}
class _CRUDoperationState extends State<CRUDoperation> {
Firestore firestore = Firestore.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CRUD"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.group_add),
onPressed: (){
showDialog(
context: context,
child: ShowCustomDialogBox(oprationName: "Add",)
);
}
)
],
),
body: Container(
padding: const EdgeInsets.all(10),
alignment: Alignment.center,
child: StreamBuilder<QuerySnapshot>(
stream: firestore.collection('Employee').snapshots(),
builder: (BuildContext context,AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError){
return new Center(
child:Text('Error: ${snapshot.error}')
);
}
if(!snapshot.hasData){
return new Center(
child:CircularProgressIndicator()
);
}
else{
var documents = snapshot.data.documents;
if(documents.length>0){
return ListView.builder(
itemCount:documents.length ,
itemBuilder: (context, index){
return Card(
child: ListTile(
leading: IconButton(
icon: Icon(Icons.edit,color: Colors.blue,),
onPressed: (){
showDialog(
context: context,
child: ShowCustomDialogBox(
documentSnapshot:documents[index],
oprationName: "Edit",
)
);
}
),
title: Text(documents[index].data['Name']),
subtitle: Text(documents[index].data['Post']),
trailing: IconButton(
icon: Icon(Icons.delete,color: Colors.red,),
onPressed: (){
firestore.collection('Employee').document(documents[index].documentID)
.delete().then((onValue){ //delete user
print("Deleted successfully");
});
}
),
),
);
}
);
}else{
return Center(
child: Text("Add Emlopyee list"),
);
}
}
}
),
),
);
}
}
//ADD OR EDIT USER DIALOG BOX
class ShowCustomDialogBox extends StatefulWidget {
final DocumentSnapshot documentSnapshot;
final String oprationName;
ShowCustomDialogBox({ this.documentSnapshot, this.oprationName});
#override
State<StatefulWidget> createState() => ShowCustomDialogBoxState();
}
class ShowCustomDialogBoxState extends State<ShowCustomDialogBox>with SingleTickerProviderStateMixin {
TextEditingController nameController;
TextEditingController postController ;
Firestore firestore = Firestore.instance;
#override
void initState() {
super.initState();
nameController = widget.oprationName == "Edit" ? TextEditingController(text: widget.documentSnapshot.data['Name'])
: TextEditingController();
postController = widget.oprationName == "Edit"? TextEditingController(text:widget.documentSnapshot.data['Post'])
: TextEditingController();
}
launchOpration(){
if(widget.oprationName == "Edit"){
editEmployee();
}else{
addEmployee();
}
}
addEmployee(){ //Create user
if(nameController.text.isNotEmpty && postController.text.isNotEmpty){
firestore.collection("Employee").add({
'Name':nameController.text,
'Post':postController.text
})
.then((doc){
print("employee added successfully documentID :${doc.documentID}");
nameController.clear();
postController.clear();
Navigator.of(context).pop();
});
}
else{
print("Please all fields");
}
}
editEmployee(){ //Update User
firestore.collection('Employee').document(widget.documentSnapshot.documentID).updateData({
'Name':nameController.text,
'Post':postController.text
}).then((onValue){
print("employee Edited successfully");
nameController.clear();
postController.clear();
Navigator.of(context).pop();
});
}
#override
void dispose() {
nameController.dispose();
postController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(8.0),
height: MediaQuery.of(context).size.height/2.5,
width: MediaQuery.of(context).size.width,
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("${widget.oprationName} Employee"),
SizedBox(height:10),
TextField(
controller: nameController,
decoration: InputDecoration(
hintText: "Enter Name",
border: OutlineInputBorder()
),
),
SizedBox(height:10),
TextField(
controller: postController,
decoration: InputDecoration(
hintText: "Enter Post",
border: OutlineInputBorder()
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 10.0, top: 0.0,),
child: ButtonTheme(
height: 35.0,
minWidth: MediaQuery.of(context).size.width/3.5,
child: RaisedButton(
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
splashColor: Colors.white.withAlpha(40),
child: Text(
widget.oprationName,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: () {
launchOpration();
},
)
)
),
],
)
),
),
);
}
}

How to implement drag and drop with flutter

How can I move my container or any other widgets on flutter around the screen and drop at some locations?
I found flutter widgets Draggable and DragTarget. How to use them to implement the drag and drop?
Draggable and DragTarget allow us to drag a widget across the screen.
A Draggable widgets gives the ability to move to any other widget while the DragTarget acts as the sink or drop location for a Draggable widget.
Find the below code sample using which I implemented a simple odd-or-even game
Hell yeah, I'm a Game Developer ◕‿↼
import 'package:flutter/material.dart';
import 'dart:math';
class OddOrEven extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _OddOrEvenState();
}
}
class _OddOrEvenState extends State<OddOrEven> {
bool accepted = false;
Color dotColor = Colors.blue;
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();
int val = 0;
int score = 0;
#override
Widget build(BuildContext context) {
// assign a random number to value which will be used as the box value
val = Random().nextInt(100);
return Scaffold(
key: scaffoldKey,
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
// just a score and mock player name indicator
Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Center(
child: Chip(
avatar: CircleAvatar(
backgroundColor: Colors.teal,
child: Text(
score.toString(),
style: TextStyle(color: Colors.white),
),
),
label: Text(
'Player Alpha',
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
fontStyle: FontStyle.italic),
),
),
),
),
),
// here comes our draggable.
// it holds data which is our random number
// the child of the draggable is a container reactangural in shape and
//
Draggable(
data: val,
child: Container(
width: 100.0,
height: 100.0,
child: Center(
child: Text(
val.toString(),
style: TextStyle(color: Colors.white, fontSize: 22.0),
),
),
color: Colors.pink,
),
// This will be displayed when the widget is being dragged
feedback: Container(
width: 100.0,
height: 100.0,
child: Center(
child: Text(
val.toString(),
style: TextStyle(color: Colors.white, fontSize: 22.0),
),
),
color: Colors.pink,
),
// You can also specify 'childWhenDragging' option to draw
// the original widget changes at the time of drag.
),
// and here this row holds our two DragTargets.
// One for odd numbers and the other for even numbers.
//
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 100.0,
height: 100.0,
color: Colors.green,
// Even holder DragTarget
//
child: DragTarget(
builder: (context, List<int> candidateData, rejectedData) {
print(candidateData);
return Center(
child: Text(
"Even",
style: TextStyle(color: Colors.white, fontSize: 22.0),
));
},
// On will accept gets called just before it accepts the drag source.
// if needed, we can reject the data here. But we are not doing that as this is a GAME !!! :)
onWillAccept: (data) {
print("Will accpt");
return true; //return false to reject it
},
// On accepting the data by the DragTarget we simply check whether the data is odd or even and accept based on that and increment the counter and rebuild the widget tree for a new random number at the source.
onAccept: (data) {
print("On accpt");
if (data % 2 == 0) {
setState(() {
score++;
});
// How did you manage to score 3 points😮
// Congrats. You won the game.
if (score >= 3) {
showDialog(
context: context,
builder: (BuildContext context) {
return new AlertDialog(
title: Text("Congrats!!"),
content: Text("No-brainer...😮"),
actions: <Widget>[
FlatButton(
child: Text("Ok."),
onPressed: () {
Navigator.of(context).pop();
setState(() {
score = 0;
});
},
)
],
);
});
}
} else {
setState(() {});
}
},
),
),
// And here is the Odd-holder
Container(
width: 100.0,
height: 100.0,
color: Colors.deepPurple,
child: DragTarget(
builder: (context, List<int> candidateData, rejectedData) {
return Center(
child: Text(
"Odd",
style: TextStyle(color: Colors.white, fontSize: 22.0),
));
},
onWillAccept: (data) {
return true;
},
onAccept: (data) {
if (data % 2 != 0) {
setState(() {
score++;
});
if (score >= 10) {
showDialog(
context: context,
builder: (BuildContext context) {
return new AlertDialog(
title: Text("Congrats!!"),
content: Text("No-brainer...😮"),
actions: <Widget>[
FlatButton(
child: Text("Thanks"),
onPressed: () {
Navigator.of(context).pop();
setState(() {
score = 0;
});
},
)
],
);
});
}
} else {
setState(() {});
}
},
),
)
],
)
],
),
),
);
}
}
If you need to drop at a non-fixed location (Draggable without a DragTarget), this can also be implemented with Stack()/Positioned() using renderbox sizing, as per How to move element anywhere inside parent container with drag and drop in Flutter?