Close AlertDialog on Navigating back from second screen and refresh page flutter - flutter

I have a method which check if the current users location is set, if not, open an alert dialog with two buttons: Cancel and Update Profile. the onPressed of the Update Profile button navigates to a second screen with a form to update users location. The issue is: if the user clicks on the Update button and update the location, on clicking back button, the first page is displayed with the alert dialog still open. Expectation: on closing the back button and on updating the location, the back button opens the first screen and refreshes the whole page, getting the new location setting.
See code: FIRST SCREEN (HOME SCREEN)
#override
void initState() {
super.initState();
getUserDetails();
}
updateProfileLocationPrompt(BuildContext context) {
Widget cancelButton = FlatButton(
child: Text("Cancel",
),
onPressed: () {
Navigator.of(context).pop(true);
},
);
Widget updateProfileButton = FlatButton(
child: Text("Update",
),
onPressed: () {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (context) => SettingsScreen()));
},
);
AlertDialog alert = AlertDialog(
title: Text("Update location",
),
content: Text(
"Please Update you location",
),
actions: [
cancelButton,
updateProfileButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
getUserDetails() async {
var firebaseUser = FirebaseAuth.instance.currentUser;
DocumentSnapshot value = await FirebaseFirestore.instance
.collection(Str.USERS)
.doc(firebaseUser.uid)
.get();
if (value.data()[Str.ADDRESS].toString() == null ||
value.data()[Str.ADDRESS].toString() == "") {
return updateProfileAndLocationPrompt(context);
} else {
setState(() {
searchLocationAddress = value.data()[Str.ADDRESS].toString();//got from firebase
getItems();
});
}
return;
}
SECOND SCREEN - SETTINGS SCREEN
Normal page with textfields for updating location to the firebase.
The issue really: How do I navigate back to home screen, refresh home screen with the new data and reload the page thus not opening the dialog as the check on location once set should not open the dialog.
Currently, even if i navigate from the dialog to the second screen, the alert dialog is still open, home screen is not refreshed with new data.

Try
Widget updateProfileButton = FlatButton(
child: Text("Update",
),
onPressed: () async {
Navigator.pop(context);
await Navigator.of(context)
.push(new MaterialPageRoute(builder: (context) => SettingsScreen()));
setState((){});
},
);

If you want to dismiss the alert dialog, then you should pop from it right when they navigate to the next screen. To rebuild the home screen once you click back, you can use a callback, so once you press the back button it will fire the callback that's declared in the home screen.
Home Screen
void rebuildPage() {
setState(() {});
}
onPressed: () {
Navigator.pop(context);
Navigator.of(context)
.push(new MaterialPageRoute(builder: (context) => SettingsScreen(onPressed: rebuildPage)));
},
Settings Screen
final Function onPressed;
SettingsScreen({ this.onPressed });
AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
onPressed();
},
)
),

Related

Pass value when dialog closed

I'm trying to create an app in Flutter.
When a particular button is pressed a Dialog shows up. In the dialog, the user can write to TextField. I want to use this text in the previous screen when the dialog is closed with pop().
Is there any way to do it?
try this:
showDialog(
context: context,
builder: (context) => Dialog(),
).then((result){
// use the result here
});
and in dialog pop like this:
Navigator.pop(context, result);
You can await to get data from button. also You can pass data .pop(YourValue)
onPressed: () async {
final data = await showDialog(
context: context,
builder: (context) {
final TextEditingController controller =
TextEditingController(); // this can be outside to get direct text from it
return AlertDialog(
content: TextField(
controller: controller,
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(controller.text);
},
child: Text("Close"))
],
);
},
);
if (data != null) {
//your operation
}
print(data);
},

flutter) How can I make the dialog disappear when the back button is pressed?

I used a dialog to prevent the backbutton pressed like following
WillPopScope(
onWillPop: () async => await onBackPressed(context:context, msg: 'back?')
Future<bool> onBackPressed(
{required BuildContext context, required String msg}) async {
bool willLeave = false;
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('$msg'),
actions: <Widget>[
TextButton(
child: const Text("OK"),
onPressed: () {
willLeave = true;
Navigator.of(context).pop();
},
),
TextButton(
child: const Text("No"),
onPressed: () => Navigator.of(context).pop())
]));
return willLeave;
}
By the way, when the dialog poped up, the dialog does not disappear although the button is pressed.
Does dialog disappear only the button or background screen tapped?
Can't I make it to disappear with the real back button?
Help me, please.. Thank you

How to dismiss AlertDialog after Navigator.push?

I am call Navigator.push() after user press button on AlertDialog. But when user press button AlertDialog remain open and on top of new page.
How to dismiss AlertDialog after user press button?
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('This is a demo alert dialog.'),
Text('Would you like to approve of this message?'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Approve'),
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page()),
);
Navigator.of(context).pop();
},
),
],
);
},
);
}
await _showMyDialog();
The comment saying to call pop is probably the easiest way to do this.
Another thing to consider next is if you want them to be able to stay on the same page. Here is a way to do both of these if you get beyond the => NewPage() style of navigation on your app. It's more commonly used for Drawers, of course.
Happy coding!
onTap: () {
newRouteName = "/form_check";
// if the current route is the exact location we're at (first on the stack), mark that
Navigator.popUntil(context, (route) {
if (route.settings.name == newRouteName) {
isNewRouteSameAsCurrent = true;
} else {
isNewRouteSameAsCurrent = false;
}
return true;
});
// if it isn't, go to the new route
if (!isNewRouteSameAsCurrent) {
Navigator.pushNamed(context, newRouteName);
}
// again if it is, just pop the drawer/dialog away
else {
Navigator.pop(context);
}
}

refresh data on home page using future builder on button click - flutter

i have an app with two screens, home and update page.
The home page displays a list of items and the update page updates the items.
I am having difficulties refreshing the home page to display current updates when I pop back to it.
How can I refresh the home page when I route back to it.
See the code to navigate to update page
// home page
// build the list widget
Widget _buildTaskWidget(task) {
return ListTile(
leading: Icon(Icons.assignment),
title: Text(task['name']),
subtitle: Text(task['created_at']),
onTap: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => UpdateTask(task: task),
),
);
await fetchAllTask();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: fetchAllTask(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List tasks = snapshot.data;
listItems = tasks;
return _buildTaskList(tasks);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Center(
child: ShowLoader(),
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddTask()));
},
tooltip: 'Add Task',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
// update page to navigate back to home page
onPressed: () async {
var res = await updateNewTask(_taskTextInput.text,
_vendorTextInput.text, _amountTextInput.text, id);
print(res);
Navigator.pop(context);
},
FutureBuilder only runs the asynchronous task when its parent is built. To force a rebuild, you can call setState() after Navigating to the next page. Doing so refreshes the current Screen before navigating to the next.
Navigator.of(context).push(...).then((_) => setState(() {}));
Another approach that you can also consider looking into is with the use of StreamBuilder - this Widget rebuilds when change in Stream is detected.

Tap is recognized multiple times

I have a Flatbutton which, when pressed should display an Image with an external link. (when the image is pressed, the external link should be opened).
Anyhow, when I press the button, the link of the Image is immediately opened and the application remains in an error state.
Widget buildWithImage(BuildContext context) {
return FlatButton(
onPressed: () async {
Map<String, String> parameter = {
"id": news.id.toString(),
"type": "image",
};
String uri = Request().getNewsDocumentUri(parameter);
Navigator.push(context, MaterialPageRoute(builder: (context) {
if (news.externalLink != null && news.externalLink.isNotEmpty) {
return Container(child: GestureDetector(
onTap: _launchURL(news.externalLink), // TODO Bug, Tap of previous Button is immediately recognized
child: Image.network(uri),
));
}
return Image.network(uri);
}));
},
child: Text(news.text));
}
How can I avoid this behaviour?
onTap: _launchURL(news.externalLink),
should be
onTap: () => _launchURL(news.externalLink),
so that it waits for an input THEN launches url