malfunction in my flutter app while dealing with dialogues - flutter

I use these dialogues for confirmation actions in which they return a true if the user confirmed to proceed with an action or false if they canceled.
For example, a logout action goes like so
GestureDetector(
onTap: ()async{
final bool result=await showDialog(
context: context,
builder: (dialogueContext) => ActionDialogue(text: 'Are you sure you want to logout?',button: 'Logout'),
);
if(result==true){
await _auth.signOut();
Navigator.pop(context);
}
},
child: Text(
'Logout',
style: TextStyle(color: Colors.grey[700],fontSize: 20),
),
),
This is what it appears on the Ui
The issue is that sometimes it decides to go rogue and return a dialogue with no text on its attributes like so.
This happens either on the buttons or the confirmation text. What could be the issue or what am i doing wrong.

Related

passing a function as a parameter to a regular class in flutter

I am trying to pass a function to a regular class (not a widget class) in flutter and inside that class, I have a dialog box. I want to call the dialog box and when the user presses a button the function is passed as a parameter that should trigger.
This is my regular class code
import 'package:finsec/core/res/strings.dart';
import 'package:flutter/material.dart';
import '../../../../core/res/text_sizes.dart';
import '../../data/repositories/app_database.dart';
class ShowDialog {
final void Function() onPressCallback;
BuildContext context;
ShowDialog (this.onPressCallback, this.context) ;
Future<String> showMyDialog() async {
return showDialog<String>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Income Data'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Do you want to apply these changes for future income transactions?',
style: TextStyle(
fontSize: text_size_18,
),
),
Text(
'\nPress NO if changes are only for this week income. Press Yes to apply changes to future weeks.',
style: TextStyle(
fontSize: text_size_18,
),
),
],
),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, successful);
},
child: const Text(cancelButton),
),
TextButton(
onPressed: () {
onPressCallback();
Navigator.pop(context, successful);
},
child: const Text(noButton),
),
TextButton(
onPressed: () {
onPressCallback();
Navigator.pop(context, successful);
},
child: const Text(yesButton),
),
],
);
},
);
}
}
I am calling ShowDialog class like this in my widget class. Below is the function call
CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () async {
await ShowDialog(
await database.deleteIncomeData(transaction),
context,
);
},
),
My code is working but not as expected. When I pass my function as a parameter, the database.deleteIncomeData(transaction) executes immediately and my showMyDialog() function in ShowDialog class doesn't get called. When I pass a function as a parameter to ShowDialog class, I don't want the function to execute immediately. I want my dialog box function to be called and show a dialog box. When the user presses a button on the dialog box, then the function parameter should execute.
Can someone help me how to modify my code to accomplish what I described above? Thanks in advance!
I recommend learning more about Future and async/await.
Be careful, because your class ShowDialog is waiting for two parameters, one is a Function and the other is the context.
There are some errors in this line
await ShowDialog(
await database.deleteIncomeData(transaction),
context,
);
First, you don't need to await because here you are calling the constructor. You have to call the showMyDialog method.
await ShowDialog(
await database.deleteIncomeData(transaction),
context,
).showMyDialog();
So, in that case, you will have something to await. The result of showMyDialog.
And the second one is that you are not passing a Function to the constructor, you are passing the value that await database.deleteIncomeData(transaction) returns.
(Unless the value that returns is a Function, in that case, it is ok)
And to fix that you have to pass a Function that calls database.deleteIncomeData(transaction)
await ShowDialog(
() => await database.deleteIncomeData(transaction),
context,
).showMyDialog();

How to pop out double alert message

I am new to Flutter. I made my first pop out confirmation alert dialog (Figure 1) but I want to pop another alert dialog window after.
What I am trying to achieve, it's the following: after I click Yes (Figure 2) the app would lead me to my homescreen and pop out another alert dialog.
You could create a method for the second Alert to show up, and call it when you click "YES" on the first one.
void showSecond(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text("Thank you for paying with us"),
content: Icon(Icons.check_circle_outline),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Okay'),
),
],
),
);
}
and your onPressed() of "YES" in the first alert should look something like:
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const SuccessPay()));
showSecond(context);
},
It was a bit hard to replicate your code from an image, so if something it's not accurate let me now. For the next time, post your code in a code block instead of a picture :)
you can call showAlertDialog to show second popup.(you can create new method to show second popup as content is different)This line can be added after
Navigator.of(context).pop() of first popup
You can use the .then() method. Call it if the user pressed the "YES" button.
Add value when poping your dialog like this Navigator.of(dialogCtx).pop(true);
showDialog(
context: context,
builder: (dialogCtx) => AlertDialog(
// title:
// content:
),
actions: [
TextButton(
onPressed: () {
Navigator.of(dialogCtx).pop(false);
},
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.of(dialogCtx).pop(true);
},
child: const Text('YES'),
),
],
),
).then(
(value) => {
if (value == true)
{
// display the next dialog with the scaffolds context
},
},
);

Flutter FlushBar does not work if I have to pre-process data

I am trying to build a form in Flutter. A user enters a value and clicks on a button, I run some basic validation on that value then show an AlertDialogue as a confirmation. If the user clicks on confirm I want to attempt an API call, get the result and display the result of that API call to let the user know what happened.If I display a Flushbar with hardcoded values it works. But If I try to do some string manipulation on the object first the Flushbar does not display. If I try to print the response from the function right into the Flushbar that also does not work.
Any advice on why this problem is occurring in the first place, and what would be the best way to solve it?
Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
textStyle: TextStyle(
fontSize: 30,
),
primary: Colors.lightGreen, // background
onPrimary: Colors.white, // foreground
),
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate())
{
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Confirmation'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('Please confirm your action'),
Text('Would you like to buy ' + finalValue.toString() + ' worth of merchandise'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('Confirm'),
onPressed: () {
Navigator.of(context).pop();
var response = bb.trade(_character, finalValue, true); //API CALL
*//String resp = response.body.split(',')[1].split(':')[1];
//resp = resp.substring(1);
//resp = resp.split('.')[0];
//print(resp);* //The real string manipulation we want to do but then flushbar does not display
Flushbar(
title: "Result",
message: "lol"+response.body.toString(), //FLUSHBAR DOES NOT DISPLAY AT ALL
duration: Duration(seconds: 5),
)..show(context);
},
),
],
);
},
);
}
},
child: Text('Buy'),
),
),
I Think the problem is that you are trying to access data from API call immediately , however data coming over API call must be awaited for.
and it is preferred to pop after showing the flush bar .
so if bb.trade(_character, finalValue, true); return future you should do like this
onPressed: () async {
var response = await bb.trade(_character, finalValue, true);
Flushbar(
title: "Result",
message: "lol"+response.body.toString(),
duration: Duration(seconds: 5),
)..show(context).then((value) => Navigator.pop(context));
},

on pressing back button on device my app should close without going to any previous screens in Flutter

I am wondering if anyone knows how to use the device back button to exit the app without going back to any previous pages/routes.
Future<bool> _onBackPressed() {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Do you want to exit an App'),
actions: <Widget>[
new GestureDetector(
onTap: () => Navigator.of(context).pop(false),
child: Text("NO"),
),
SizedBox(height: 16),
new GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => WelcomeScreen()),
);
},
child: Text("YES"),
),
],
),
) ??
false;
}
To programmatically exit flutter apps, you need to pop the systemNavigator like follow :
SystemNavigator.pop()
SystemNavigator is available after importing Services :
import 'package:flutter/services.dart';
An other method is to use exit(0) which would terminate the app but is usually not user Interface friendly especially on iOS.
You can exit your app using following ways:
SystemChannels.platform.invokeMethod<void>('SystemNavigator.pop', animated)
exit(0)
SystemNavigator.pop()
Although all three ways works but the preferred way of doing this is to use SystemNavigator.pop(). The method looks like this:
static Future<void> pop({bool animated}) async {
await SystemChannels.platform.invokeMethod<void>('SystemNavigator.pop', animated);
}
exit(0)is not a recommended way as it immediately terminates the process running in dart VM and looks a bit like your app is crashed.

How to close an Alert dialog without a button in FLUTTER

I want to show a circle indicator when the user presses the login button. But sometimes an error can occur such as a Wrong email or wrong password. In that case, the circle indicator should be stopped and the error message should be shown. There is no button in circle indicator alert dialog. I want it to automatically close when an error found
onPressed: () async {
AuthResult user;
progressIndi();
try {
user = await _auth.signInWithEmailAndPassword(email: email, password: pass);
} catch (err) {
finderror(err.code);
}
finderror function will find the error message to show.
progressIndi() function will show the alert dialog. I tried to implement it with stacks. But it's only showing changes when I close the dialog box and press the login button again.
void progressIndi() {
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return IndexedStack(
index: isError,
children: <Widget>[
AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(
margin: EdgeInsets.only(left: 5),
child: Text(" Loading")),
],
),
),
AlertDialog(
title: Text("Error Found"),
content: Text(errorMessage),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Try Again"),
onPressed: () {
Navigator.of(context).pop();
isError = 0;
},
),
],
),
],
);
},
);
}
I know that alert dialog can be closed using the button and Navigator.of(context).pop() .
Please, anyone, give me a hint to close the alert dialog from outside without a button.
You can remove the dialog when an error occurs by calling Navigator.of(context).pop() just after the exception occurs and then show another dialog for error. Hope this helps.
AuthResult user;
progressIndi();
try {
user = await _auth.signInWithEmailAndPassword(email: email, password: pass);
} catch (err) {
//Use pop here.
Navigator.of(context).pop();
//make findError open another dialog.
finderror(err.code);
}