flutter alert dialog not updating from outside the function - flutter

i want to make a download progress message inside the alert dialog but state not updating inside the the modal
the is the download function using dio
downloadBook() async {
Directory tempDir = await getTemporaryDirectory();
var response = await dio.download(widget.bookModel.acf.bookLink,
tempDir.path + '/books/' + widget.bookModel.title.rendered + '.epub',
options: Options(
responseType: ResponseType.bytes,
), onReceiveProgress: (actualbytes, totalbytes) {
var percenatge = actualbytes / totalbytes * 100;
_percentageBar = percenatge / 100;
setState(() {
downloadMessage = 'Downloading... ${percenatge.floor()} %';
});
});
}
and this is the alert dialogue function
void _showDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Alert!!"),
content: new Text(downloadMessage),
actions: <Widget>[
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
and i made call like this inside the text button but the message stuck on 0% and not updated;
onPressed: () {
// _showDialog(context);
downloadBook();
showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: new Text("Alert!!"),
content: new Text(downloadMessage),
actions: <Widget>[
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
);
},

You can use
StatefullBuilder
widget top of your alert dialog and pass
setState
to it where you call it.
In this way you can access to State from outside.

As I understood from your question, you are trying to have a different state for your alert dialog, so I will just update your code regarding the alertDialog and you can do what you want after that.
showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: new Text("Alert!!"),
content: new Text(downloadMessage),
actions: <Widget>[
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
);
So you can use setState for any progress you want inside.

Related

Flutter: Set global variable using OK button on AlertDialog in StatefulBuilder

How to set global variable using OK button on AlertDialog in StatefulBuilder?
String stringMain = "My String";
Future<String?> dialogChangeMainContent(BuildContext context) {
return showDialog<String>(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: const Text('AlertDialog description'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, 'OK');
setState(() {
// setState2();
stringMain = "New String";
});
},
child: const Text('OK'),
),
],
);
});
});
}
I changed StatefulWidget from StatelessWidget, but nothing changes. What I know is the problem is because the button is in the StatefulBuilder. If using BLoC etc, it's too wasteful for only small applications.
I found a way to solve my problem, redrawing (refreshing) the Text (or other widget) in a Stateless Widget from an AlertDialog in a StatefulBuilder. By creating a setState with a different name, for example setStateTarget.
Without having to rebuild the entire page, or without state management like BLoC. My code:
String stringMain = "My String";
#override
Widget build(BuildContext context) {
return Column(
// ....
children: [
StatefulBuilder(builder: (BuildContext context, setStateTarget) {
return Column(children: [
Text(stringMain), // <--- target
TextButton(
onPressed: () => dialogChangeMainContent(context, setStateTarget),
child: const Text('Show Dialog'))
]);
})
],
);
}
Future<String?> dialogChangeMainContent(BuildContext context, StateSetter setStateTarget) {
return showDialog<String>(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: const Text('AlertDialog description'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, 'OK');
setStateTarget(() {
// setState2();
stringMain = "New String";
});
},
child: const Text('OK'),
),
],
);
});
});
}

Calling alert dialog where no context is available

I am fetching data from api in getSmartTags()
And if error occurs, I want to show the dialog.
I made the code below but this error comes.
lib/main.dart:1218:14: Error: Undefined name 'context'. context: context,
^^^^^^^
#override
Widget build(BuildContext context) {
context is in build function, but I want to show the alert dialog not in build function, is it possible?
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('This is a demo alert dialog.'),
Text('Would you like to approve of this message?'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future getSmartTags() async {
var url = Uri.https(apiServer,'/api/smarttags');
try{
var resp = await http.get(url);
throw Exception();
}catch(e){
_showMyDialog();
}
}
Try this
//add context as parameter
Future<void> _showMyDialog(BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('This is a demo alert dialog.'),
Text('Would you like to approve of this message?'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future getSmartTags() async {
var url = Uri.https(apiServer,'/api/smarttags');
try{
var resp = await http.get(url);
throw Exception();
}catch(e){
_showMyDialog(context); //add this too
}
}

Flutter - Custom back button doesn't work

I have an alertdialog which is supposed to return a bool depending on the user's choice, the message gets removed, but the back button isn't working!
Future<bool?> showwarning(BuildContext context) async {
showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: new Text("Alert!!"),
content: new Text("Return To Main Page?!"),
actions: [
TextButton(
child: new Text("Yes"),
onPressed: () {
Navigator.pop(context, true);
},
),
TextButton(
child: new Text("Nope"),
onPressed: () {
Navigator.pop(context, false);
},
)
],
));
}
Widget build(BuildContext context) {
// TODO: implement build
return WillPopScope(
onWillPop: () async {
final user_decision = await showwarning(context);
return user_decision ?? false;
},
Future<bool?> showwarning(BuildContext context) async {
return showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: new Text("Alert!!"),
content: new Text("Return To Main Page?!"),
actions: [
TextButton(
child: new Text("Yes"),
onPressed: () {
Navigator.pop(context, true);
},
),
TextButton(
child: new Text("Nope"),
onPressed: () {
Navigator.pop(context, false);
},
)
],
));
}
Widget build(BuildContext context) {
// TODO: implement build
return WillPopScope(
onWillPop: () async {
final user_decision = await showwarning(context);
return user_decision ?? false;
},
The problem is that I wasn't returning anything from showwarning function , hence, it was always false!

wait until showdialog is closed flutter

I am trying to get the location permissions and I want to display a message before requesting the permission. but when I run the APP it doesn't wait until I close the showdialog
Future<void> checkPermission() async {
var status = await Permission.location.status;
print(status.toString());
if (status.isUndetermined) {
await showAlertPopup(context, '',
'OK')
.then((val) {
var statuses = Permission.location.request();
print(statuses);
});
}
if (status.isDenied ||
status.isPermanentlyDenied ||
status.isRestricted ||
status.isUndetermined) {
await showAlertPopup(context, '',
'error')
.then((val) {
openAppSettings();
});
}
if (status.isGranted) {
_geoAlowed = true;
}
}
and this is my code to display the popup
showAlertPopup(BuildContext context, String title, String detail) async {
showDemoDialog({BuildContext context, Widget child}) async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return child;
});
}
return showDemoDialog(
context: context,
child: AlertDialog(
title: Text(title),
content: Text(detail),
backgroundColor: grayLight,
actions: [
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.pop(context, 'OK');
},
),
],
),
);
}
As per your question, you want to request permission when user clicks 'OK' button in dialog.
You can create a callback, that is when user clicks 'OK'
showAlertPopup(context, '','OK', (){
//Code you want to execute when user clicks 'OK'
});
And little changes in you showAlertPopup
showAlertPopup(BuildContext context, String title, String detail, Function onClick) async {
showDemoDialog({BuildContext context, Widget child}) async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return child;
});
}
return showDemoDialog(
context: context,
child: AlertDialog(
title: Text(title),
content: Text(detail),
backgroundColor: grayLight,
actions: [
FlatButton(
child: Text('OK'),
onPressed: () {
//Your callback
onClick();
Navigator.pop(context, 'OK');
},
),
],
),
);
}

close Simple Dialog in flutter when setState needs to called

I'm having a problem calling Navigator.of(context).pop() on my onPressed property in SimpleDialogOption widget. I need to set the state and dismiss the dialog. But calling setState is preventing my dialog to close. Without setState the dialog closes. Here is my dialog
WidgetsBinding.instance.addPostFrameCallback((_) {
showDialog(
builder: (BuildContext context) {
return SimpleDialog(
children: _children(suburbs),
backgroundColor: Colors.white,
title: Text('Pick your suburb'),
);
},
context: context);
});
and the method I use for the list of the Dialog:
List<Widget> _children(List<Suburb> suburbs) {
return suburbs
.map((suburb) => SimpleDialogOption(
onPressed: () {
print('#####################');
setState(() {
postcode = suburb.name;
});
Navigator.of(context).pop();
},
child: Text(suburb.name)))
.toList();
}
you can await until the return value comes from the navigator.pop,
and then call a setState
WidgetsBinding.instance.addPostFrameCallback((_) async {
postcode = await showDialog(
builder: (BuildContext context) {
return SimpleDialog(
children: _children(suburbs),
backgroundColor: Colors.white,
title: Text('Pick your suburb'),
);
},
context: context);
setState(() {
postcode;
});
});
List<Widget> _children(List<Suburb> suburbs) {
return suburbs
.map((suburb) => SimpleDialogOption(
onPressed: () {
print('#####################');
Navigator.of(context).pop(suburb.name);
},
child: Text(suburb.name)))
.toList();
}