Data not being passed in Navigator.pop - flutter

I'm trying to pass data from a screen with navigator.pop, it shows the result in the second screen, but in the first screen the data is always null. I tried some things on it but didn't work.
Here I'm calling the second screen:
onPressed: () async {
final result = await push(context, PickMaterialPage());
print("Result $result");
},
In this one is when I want to pass the data for the first screen with navigator.pop, It's an object.
Card card(int index, context) {
RequisicaoMaterial material = materiais[index];
try {
return Card(
color: Colors.grey[300],
elevation: 6.0,
margin: new EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
child: GestureDetector(
onTap: () => pop(context, material),
child: CustomListTile(
Icons.shopping_cart_outlined,
'${material.codMaterial} - ${material.nomeMaterial}',
'${material.codUnidade} - ${material.sigla} - ${material.classificacao}',
null,
),
));
} catch (e) {
print(e);
}
I don't want to use constructor in this one, i needed to make it simple and only get the picked data to show in the first screen.
output $result = null

PUSH THE SCREEN
String result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => AddTenantToRoomFlyPage(),
),
);
POP THE SCREEN
Navigator.pop(context, "RETURN VALUE");

Do it like this
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PickMaterialPage(),
)).then((value) => print(value)),

Related

Returning data from .pop() to use it anywhere

I have written a code that return bool type variables. Whether you like the movie. If you like the movie then it returns true, if you don't like the movie then it returns false. But since the .pop() method works in ElevatedButton, I cannot reach it from another class. How can I reach the value?
ElevatedButton(
child: Text(
"Go to new page"
),
onPressed: () async {
final answer = await Navigator.of(context).push<bool>(
MaterialPageRoute(
builder: (context) {
return VideoScreen("Did you like the video?");
},
)
);
},
),
However, I cannot say like:
ElevatedButton(
child: Text(
"Go to new page"
),
onPressed: () async {
final answer = await Navigator.of(context).push<bool>(
MaterialPageRoute(
builder: (context) {
return VideoScreen("Did you like the video?");
},
)
);
},
),
Text(answer)
],
);
So how can I reach that value? Callback or something? Thanks in advance
Use can pass value to parent route while pop like
Navigator.of(context).pop(YourValue);
While you push make sure to await.
final result = await Navigator.of(context)....;
print(result);

FLUTTER button onpressed navigator push got errors

I've made a button to send data to firebase. I want when the button is pressed, the button is not only to send data to firebase, but I want the button makes users can go back to the homepage.
I used setData for sending the data, and I used Navigator.push, but the navigator push is errors.
final sdButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(5),
color: const Color(0xFFD3DEDC),
child: MaterialButton(
padding: const EdgeInsets.fromLTRB(20,15,20,15),
minWidth: MediaQuery.of(context).size.width,
onPressed: setData {
Navigator.push(context,
MaterialPageRoute(
builder:(context) => Homepage(),));
},
and this is the code for setData
setData(){
dref.child(user!.uid).set({
'user_id' : user!.uid,
'intime' : '15.17'
}
);
}
onPressed: () {
setData();
Navigator.push(context, MaterialPageRoute(
builder:(context) => Homepage(),));
},
Please update onPress method to like as below.
onPressed: (){
setData();
Navigator.push(context,
MaterialPageRoute(
builder:(context) => Homepage(),));
},

How to wait for value before calling method Flutter/Dart

I am having a pretty hard time with certain actions in flutter. I currently have a method in an outside class that updates a db that my widget relies on for displaying info. I am correctly updating the values in the db and updating the UI correctly. BUT I am having a hard time getting an input first, THEN having that method function. I have tried having it all in the same body and no dice, I have tried to have the addStock method show the input and does not work. The only thing that has been a ban-aid has been to use Navigator.push to the screen again or using a time delayed. Both have produced undesired consequences. I have also tried having the addStock method inside the displayAmountToADD on pressing okay and does not update UI.
//a button inside the UI
onPressed: () async {
displayAmountToAdd(context, index);
setState(() {});
},
....
Future<void> displayAmountToAdd(
BuildContext context,
int index,
) async {
final _textFieldController = TextEditingController();
double materialKG = 0;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Enter amount to add'),
content: Row(
children: <Widget>[
Expanded(
child: TextField(
onChanged: (materialQuanity) {
materialKG = double.parse(materialQuanity);
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "KG"),
),
),
],
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () {
materialKG = double.parse(_textFieldController.text);
addStock(context, mapM[index]['quanity'], mapM[index]['name'],
materialKG);
Navigator.pop(context);
},
),
TextButton(
child: Text("Cancel"),
onPressed: () {
Navigator.pop(context);
})
],
);
},
);
//return Future.delayed(Duration(seconds: 4),()=>materialKG); //TRYING TO AVOID THIS
}
//outside the ui file
addStock(
BuildContext context,
double currentQuanity,
String name,
double amountToAdd
) async {
//final db = await database;
double newStock;
late double materialKG;
newStock=currentQuanity+amountToAdd;
await db.rawUpdate(
'UPDATE materials SET quanity = $newStock WHERE name = "$name" ');
mapM = await db.query('materials'); //update values
//the following is only because setState is not working properly on other screen
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Added $amountToAdd KG to $name"),
));
}
displayAmountToAdd and showDialog method are future. Use await before theses to hold method to finish.
A sample example:
const oneSecond = Duration(seconds: 1);
// ยทยทยท
Future<void> printWithDelay(String message) async {
await Future.delayed(oneSecond);
print(message);
}
Learn more about async-await.

Only update UI when there are changes in the server, using streambuilder

I am using streambuilder to check whether a new order is placed or not.
I am checking the order status, if the order status is unknown I want to show a pop up, which works fine. but if i don't select an option to update the order status, streambuilder refreshes after a few seconds, and show another pop up on top of it.
Get Orders Function:
Future<Orders> getOrders() async {
String bsid = widget.bsid;
try {
Map<String, dynamic> body = {
"bsid": bsid,
};
http.Response response = await http.post(
Uri.parse(
"**API HERE**"),
body: body);
Map<String, dynamic> mapData = json.decode(response.body);
Orders myOrders;
print(response.body);
if (response.statusCode == 200) {
print("Success");
myOrders = Orders.fromJson(mapData);
}
return myOrders;
} catch (e) {}
}
Here's the stream function:
Stream<Orders> getOrdersStrem(Duration refreshTime) async* {
while (true) {
await Future.delayed(refreshTime);
yield await getOrders();
}}
StreamBuilder:
StreamBuilder<Orders>(
stream: getOrdersStrem(
Duration(
seconds: 2,
),
),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
CircularProgressIndicator.adaptive(),
);
}
var orders = snapshot.data.statedatas;
return ListView.builder(
itemCount: orders.length,
itemBuilder: (BuildContext context, int index) {
var orderResponse =
snapshot.data.statedatas[index].strAccept;
print(orderResponse);
if (orderResponse == "0") {
print("order status unknown");
Future.delayed(Duration.zero, () {
_playFile();
showCupertinoDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Center(
child: Text(
"#${orders[index].ordrAutoid}",
),
),
content: Row(
children: [
SizedBox(
width: 120,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty
.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(
MaterialState.pressed))
return Colors.black;
return Colors
.green; // Use the component's default.
},
),
),
onPressed: () async {
_stopFile();
Navigator.pop(context);
await changeOrderStatus(
orders[index].orid, "accept");
// setState(() {});
},
child: Text('Accept'),
),
),
SizedBox(
width: 15,
),
SizedBox(
width: 120,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty
.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(
MaterialState.pressed))
return Colors.black;
return Colors
.red; // Use the component's default.
},
),
),
onPressed: () async {
_stopFile();
Navigator.pop(context);
await changeOrderStatus(
orders[index].orid, "Reject");
// setState(() {});
},
child: Text('Reject'),
),
),
// TextButton(
// onPressed: () async {
// _stopFile();
// Navigator.pop(context);
// await changeOrderStatus(
// orders[index].orid, "reject");
// },
// child: Text('reject'),
// ),
],
),
),
);
}).then((value) {
_stopFile();
print("ENDING");
});
}
return Container();
Create a variable to check for the last known order status, outside your if statement, and when a new value comes, compare it to the old value first, then do the if statement logic.
//This is outside the stream builder:
String orderResponseCheck = "";
.
.
.
//This is inside your streambuidler, if the orderResponseCheck is still equal to "", the if statement will be executed,
//and the value of orderResponse wil be assigned to it. This will only show the alert dialog if the orderResponse status changes from the one that previously triggered it.
var orderResponse =snapshot.data.statedatas[index].strAccept;
print(orderResponse);
if (orderResponseCheck != orderResponse && orderResponse == "0") {
orderResponseCheck = orderResponse;
.
.
.
//logic same as before
You shouldn't call showCupertinoDialog (and probably _playFile()) from your build method. Wrapping it with Future.delayed(Duration.zero, () { ... }) was probably a workaround for an error that was given by the framework.
The build method can get executed multiple times. You probably want a way to run _playFile and show the dialog that isn't depending on the UI. I don't think StreamBuilder is the right solution for this.
You could use a StatefulWidget and execute listen on a stream from the initState method. initState will only be called once.
From what I'm reading, you're querying your API every two seconds.
Every time your API answers, you're pushing the new datas to your StreamBuilder, which explains why you're having multiple pop-ups are stacking.
One simple solution to your problem would be to have a boolean set to true when the dialog is displayed to avoid showing it multiple times.
bool isDialogShowing = false;
...
if (orderResponse == "0" && !isDialogShowing) {
isDialogShowing = true;
...
But there are a few mistakes in your code that you should avoid like :
Infinite loops
Querying your API multiple times automatically (it could DDOS your service if plenty of users are using your app at the same time)
Showing your Dialog in a ListView builder

The dialog box opens multiples time at a same time in flutter

whenever I click many times on wheel, open multiple dialog boxes at the same time.
I just want, it should be open after previous got dismissed.
I took an image and add animation on it and wrapped it with GestureDetector widget.
onTap: event i called alertDialogBox() method which is defined for Dialog box. watch above the gif image, and called the animation method with specific Condition
CODE:
Dialog box
alertDialogBox(BuildContext context) {
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0))),
contentPadding: EdgeInsets.only(top: 10.0),
content: Stack(
children: <Widget>[
....
],
),
);
});
}
The Wheel:
GestureDetector(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
child: new AnimatedBuilder(
animation: _animationCtrl,
child: Container(
height:MediaQuery.of(context).size.height/2.3,
width: MediaQuery.of(context).size.width/1.3,
decoration: BoxDecoration(
color: Colors.blue,
image: DecorationImage(
image: AssetImage('assets/wheel.png', ),
fit: BoxFit.contain,
),
borderRadius: BorderRadius.all(Radius.circular(130.0)),
)
),
builder: (BuildContext context, Widget _widget) {
.......
},
),
),
onTap: ()async{
await Firestore.instance.collection('Users').document(uid).get().then((DocumentSnapshot documnet){
getIsSpin=documnet['isSpin'];
});
if(getIsSpin=="0"){
if (!_animationCtrl.isAnimating) {
//applying animation
}
DateTime now = DateTime.now();
// String lastSpinTime =DateFormat("yyyy-MM-dd hh:mm:ss").format(now);
.....//here updating isSpin value=1 and also updating spining Date time to firestore
}else {
oneDayDuration();
}
}
)
After 24 hours trying to spin the wheel
oneDayDuration():
void oneDayDuration()async{
int differenceTime;
await({
....here fetching last spin date time from firestore});
....//here getting difference hours between last spining time and current time
if(differenceTime>=24){
await({......//updating ispin=0 to firbase
})
.then((result) => {
print("Now you're able to spin"),
}).catchError((err) => print(err));
}else{
print("Please wait for 24 hours");
alertDialogBox(context);
}
}
}
Maybe this is because, you are trying to show dialog Asynchronously, where you don't have to. Just remove async, it is unnecessary while showing a simple dialog.
You better create a method that runs async in the if condition, and remove async in the onTap. This will separate your dialog code with async.
It is too late to answer this question, I came across the same scenario and solved it.
This is because the alertDialogBox function is invoked by build method every time the state is changed. you need to limit it by adding a variable to class like 'isAlertboxOpened' and make opening of alertDialogBox conditional and avoid opening multiple dialog boxes.
The following code should work
class _MyHomePageState extends State<MyHomePage> {
bool isAlertboxOpened; // add this
#override
void initState(){
isAlertboxOpened = false; // add this
}
alertDialogBox(BuildContext context) async {
setState(() => isAlertboxOpened = true); // add this
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0))),
contentPadding: EdgeInsets.only(top: 10.0),
content: Stack(
children: <Widget>[
....
// when press ok button on pressed add this
onPressed:(){
// your code
setState(() => isAlertboxOpened = false);
Navigator.of(context).pop();
}
],
),
);
});
}
void oneDayDuration()async{
int differenceTime;
await({
....here fetching last spin date time from firestore});
....//here getting difference hours between last spining time and current time
if(differenceTime>=24){
await({......//updating ispin=0 to firbase
})
.then((result) => {
print("Now you're able to spin"),
}).catchError((err) => print(err));
}else{
print("Please wait for 24 hours");
isAlertboxOpened ? (){} : // add this to make this conditional
alertDialogBox(context);
}
}
}