wait until showdialog is closed flutter - 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');
},
),
],
),
);
}

Related

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!

How can I make a widget test of this method?

showAlertDialog(BuildContext context, AlertDialog alert, bool dismissible) {
if (isDialogOpened!) {
Navigator.pop(context);
isDialogOpened = false;
}
showDialog(
barrierDismissible: dismissible,
context: context,
builder: (BuildContext context) {
isDialogOpened = true;
return alert;
},
).then((_) => isDialogOpened = false);
}
This method is inside a controller of mine that I call AlertController, in mine I don't know what would be the best approach for me to be able to do my tests with this method.
I am not sure exactly what properties you intend to test, but this is an example test that will check that the isDialogOpened variable changes state. Hopefully this makes for a good starting point for your testing:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
bool? isDialogOpened = false;
showAlertDialog(BuildContext context, AlertDialog alert, bool dismissible) {
if (isDialogOpened!) {
Navigator.pop(context);
isDialogOpened = false;
}
showDialog(
barrierDismissible: dismissible,
context: context,
builder: (BuildContext context) {
isDialogOpened = true;
return alert;
},
).then((_) => isDialogOpened = false);
}
void main() {
testWidgets('test showAlertDialog function', (WidgetTester tester) async {
final scaffoldKey = GlobalKey<ScaffoldState>();
await tester.pumpWidget(MaterialApp(
home: Scaffold(
key: scaffoldKey,
appBar: AppBar(title: const Text('Test App')),
),
));
expect(isDialogOpened, false);
showAlertDialog(
scaffoldKey.currentContext!,
AlertDialog(
title: const Text('Custom Dialog'),
actions: [
Builder(
builder: (context) => IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(Icons.close),
),
),
],
),
true,
);
await tester.pump();
expect(isDialogOpened, true);
await tester.tap(find.byIcon(Icons.close));
await tester.pump();
expect(isDialogOpened, false);
});
}

flutter alert dialog not updating from outside the function

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.

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();
}