Calling alert dialog where no context is available - flutter

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
}
}

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'),
),
],
);
});
});
}

Can't access bloc in showDialog context in Flutter

I´m new in the bloc pattern. I want to show up an alert dialog when I press a button, but when I use showDialog func and showDialog I want to access Bloc from context or BlocListner doesn't contain bloc and throw error is there a way to access bloc in this situatuion
Error: Could not find the correct Provider above this BlocListener<TeacherFinancialCubit, TeacherFinancialState> Widget
#override
Widget build(BuildContext context) {
return BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if(state is! Authorize) {
return const BaBaFullScreenLoading();
}
return BlocProvider<TeacherFinancialCubit>(
lazy: false,
create: (context) => TeacherFinancialCubit(locator())..getTeacherFinancial(state.user, state.account, teacherId ?? 0),
child: _masterLayout(context),
);
},
);
}
Widget _masterLayout(BuildContext context) {
Authorize authorize = context.read<UserBloc>().state as Authorize;
return MasterLayout(
showBack: true,
floatingActionButton: authorize.account.type == master ? FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
Future.microtask(() => _showAddPaymentDialog(context));
},
) : null,
title: const Text(""),
child: WillPopScope(
onWillPop: () => Future.value(false),
child: _showTeacherFinancials(context, authorize),
),
);
}
void _showAddPaymentDialog(BuildContext context) async {
return showDialog(
barrierDismissible: false,
context: context,
builder: (_) {
return BlocListener<TeacherFinancialCubit, TeacherFinancialState>(
listener: (context, state) {
if(state is TeacherFinancialLoading) {
EasyLoadingHelper.showLoading();
}
else {
EasyLoadingHelper.dismiss();
if(state is TeacherFinancialFailed) {
EasyLoadingHelper.showToastError(context, message: state.error);
}
else if(state is TeacherFinancialSuccess) {
EasyLoadingHelper.showToastSuccess(context, message: successMessage);
Navigator.pop(context);
}
}
},
child: AlertDialog(
title: const Text(''),
content: Form(
key: addPaymentFormKey,
child: Text(""),
),
actions: [],
),
);
}
);
}
Make sure to provide the bloc to the AlertDialog. You can do something like this:
return showDialog(
...
builder: (dialogContext) => BlocProvider.value(
value: BlocProvider.of<TeacherFinancialCubit>(context),
child: BlocListener<TeacherFinancialCubit, TeacherFinancialState>(
...
),
),

show AlertDialog based on condition

I want to show a What's New style AlertDialog to inform users what has changed in my app after updating. I've created the following function to see if the app has been updated:
Future<bool> checkNewVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appVersion = packageInfo.version;
SharedPreferences prefs = await SharedPreferences.getInstance();
final String? currVersion = prefs.getString("version");
print("App version: $appVersion");
print("Current version: $currVersion");
if (currVersion == null) {
await prefs.setString("version", appVersion);
return true;
}
if (currVersion != appVersion) return true;
return false;
}
When this function is called in the build method below, the print statements output the following, but the alert dialog is not shown:
flutter: App version: 2.0
flutter: Current version: null
#override
Widget build(BuildContext context) {
if (checkNewVersion() == true) {
showDialog(context: context, builder: (_) =>
AlertDialog(
title: const Text("What's New / Que ha Cambiado"),
content: Text(updateInfo),
actions: <Widget>[
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
}
return Scaffold(
// app main menu
...
);
}
You are Performing an async operation to get the result. So when performing an async function that returns some Future you must await for it otherwise it will return you an incomplete future.
So when calling checkNewVersion()
You should await for its result like
var versionResult = await checkNewVersion();
Your code will be like
#override
Widget build(BuildContext context) {
var versionResult = await checkNewVersion();
if (versionResult) {
showDialog(context: context, builder: (_) =>
AlertDialog(
title: const Text("What's New / Que ha Cambiado"),
content: Text(updateInfo),
actions: <Widget>[
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
}
return Scaffold(
// app main menu
...
);
}
your checkNewVersion is an async function so you have to wait for its result, Try this:
#override
Widget build(BuildContext context) {
bool result = await checkNewVersion();
if (result) {
showDialog(context: context, builder: (_) =>
AlertDialog(
title: const Text("What's New / Que ha Cambiado"),
content: Text(updateInfo),
actions: <Widget>[
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
}
return Scaffold(
// app main menu
...
);
}

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.

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');
},
),
],
),
);
}