How to auto dismiss an AlertDialog box after getting GPS point? - flutter

I am trying to make a dialog box that displays "text" after getting the location and then doing... Navigator.of(context).pop(); to auto close the dialog
Help! I am starting at Flutter... here's the code
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
......
showProgressDialogGPS(BuildContext context,
{String message = 'Loading...'}) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
Future.delayed(Duration(milliseconds: 50), () {
_getPosition();
Navigator.of(context).pop();
});
return AlertDialog(
actions: [],
content: Row(
children: <Widget>[
CircularProgressIndicator(),
SizedBox(width: 20),
Expanded(child: Text(message)),
],
),
);
},
);
}
Future _getPosition() async {
await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low)
.then((value) {
print(value);
});
}
.......
Thanks guys!!!

You can modify your code like this :
Future.delayed(Duration(milliseconds: 50), () async{
await _getPosition();
Navigator.of(context).pop();
});
here you are waiting for _getPosition to be executed then the statement Navigator.of(context).pop(); will be executed.

Related

Flutter "Do not use BuildContexts across async gaps"

Basically I want to return to my LoginView when the user presses Logout in the dialog.
onSelected: (value) async {
switch (value) {
case MenuAction.logout:
final shouldLogout = await showLogOutDialog(context);
final navigator = Navigator.of(context);
if (shouldLogout) {
await FirebaseAuth.instance.signOut();
navigator.pushNamedAndRemoveUntil(
'/login',
(route) => false,
);
}
}
},
showLogoutDialog function:
Future<bool> showLogOutDialog(BuildContext context) {
return showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Sign out'),
content: const Text('Are you sure you want to sign out?'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: const Text('Logout'),
),
],
);
},
).then((value) => value ?? false);
I get this error: "Do not use BuildContexts across async gaps.".
Anyone who can help me?
Thanks in advance!
It is unsafe, try checking if the widget is not mounted as shown on the Flutter YouTube Channel.
if (!mounted) return
Navigator.of(context);

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.

CircularprogressIndicator while loading the home screen during logging in app in flutter

I was looking to show circularprogressindicator while user is being logged into device.I saw various methods online one of them was by using bool _isloading like here but here it replaced my button with curcularprogressindicator and not logged in too + I want the indicator in center of screen and other was while using futurebuilder which i don't require. So, i thinked a lot and couldn't find anything ,so if you can help me it will be very greatful.
My code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:green_earth/mainpage.dart';
import 'package:http/http.dart' as http;
Future<void> attemptSignUp(String username, String password,BuildContext context) async {
final http.Response res = await http.post(
'https://green-earth.herokuapp.com/signup',
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body:jsonEncode(<String, String>{
"email":username,
"password":password
}),
);
CircularProgressIndicator();
if (res.statusCode==200){
Navigator.of(context).pushNamed('/home');
}
else{
_showMyDialog(context,res.statusCode);
}
}
// print("res status code=${res.statusCode} $username $password ${jsonDecode(res.body)}")
Future<void> _showMyDialog(BuildContext context,int statuscode) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Error'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
statuscode==422?Text('Email ID is already taken. Please try again!'):Text('Authorisation was failed with status code $statuscode'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
calling function
GestureDetector(
onTap:(){
if(formkey2.currentState.validate()==true){
signupUsername=signupUsernameController.text;
signupPassword=signupPasswordController.text;
attemptSignUp(signupUsername, signupPassword,context);
}
},
child: PrimaryButton(
btnText: "Create Account",
),
),
Based on the answer the person provided in the other question, if you don't want the button to be replaced you could use the same logic, but use a stack instead.
Stack(
children: [
(... your login form ...),
_isLoading ? CircularProgressIndicator() : SizedBox.srink(),
],
);
You can modify it to any style you want (if you also want to blurr the bg, etc) but that is the basic approach.
Update
Change your on tap to something like this:
onTap:() async {
if(formkey2.currentState.validate()==true){
signupUsername=signupUsernameController.text;
signupPassword=signupPasswordController.text;
setState((){
_isLoading = true;
});
await attemptSignUp(signupUsername, signupPassword,context);
setState((){
_isLoading = false;
});
}
Noticed I've made onTap async to wait for the future, and also I'm using setState to simplify the example, but it means to update the UI.

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

Flutter: future not returned after closing alert dialog

I created a http method in Flutter like below:
Future<void> addProduct(Product product) {
const url = 'https://flutter-shop-3de16.firebaseio.com/products';
return http
.post(
url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFavorite,
}),
)
.then((response) {
...
notifyListeners();
}).catchError((error) {
print(error);
throw error;
});
}
I know that my url is wrong because i want to get error.
In .catchError i throw an error and in the main page by provider i used addProduct like this:
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}).then((_) {
print('after catch accoured');
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
});
}
}
I catchError i got error and i show an alert dialog.After tap on Okay button i want to execute then block so i returned showDialog because it return a future.
But i do not know why
.then((_) {
print('after catch accoured');
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
});
}
No to run after alert dialog is closed?
make sure using return showDialog<Null>() instead of return showDialog()
also have a try-catch with throw error when using json.decode() inside products provider
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
).then((value) => null);
the above then((value) => null ); will solve your problem, it would help you i think.
The then block will run after the main Future; it won't run after catchError. If you want to run a piece of code after catchError, use a whenComplete block.
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}).whenComplete(() { // This will run after execution
print('after catch accoured');
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
});
}
}
Below code should solve your issue. moving then statement after show dialog would make it work again.
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) =>
AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
).then((_) {
print('after catch accoured');
setState(() {
isLoading = false;
});
Navigator.of(context).pop();
});;
});