Is there any method that I can open an alert dialog with list of choices in flutter based on an if condition? - flutter

So basically I have a countdown timer for a minute and when the minute finishes I want an alert dialog to pop on the screen for the user e.g:
if (isCompleted) {
//open the dialog widget here
}
I can't find solutions for that. I'm only finding solutions that opens the dialog on button press.
Can anyone help?

I used this in a project of mine to display an info dialog when opening the app for the first time:
Future.delayed(Duration(milliseconds: 500), () {
showDialog(
context: context,
builder: (context) => AlertDialog(
//etc
)
You can probably wrap your widgets in a FutureBuilder (so you have access to context) with your countdown as the future argument, and, when the countdown is over, you can call showDialog from there.

Related

Why is my function preventing the dialog dismiss/pop in Flutter?

I am trying to execute a function after a dialog is dismissed/popped. I read this article How to run code after showDialog is dismissed in Flutter? and tried to do it as recommended but it wouldn't work for me.
This is how I call my dialog:
Future<void> onDeleteEventData(BuildContext context) async {
final title = context.messages.settings.offline.deleteEventData;
final subTitle = context.messages.settings.offline.deleteEventDataDesc;
final res = await showDeleteDialog(context,
title: title,
subTitle: subTitle);
if (res == true){
context.read<EventDownloadTileController>().deleteEventRelatedData();
}
}
The showDeleteDialog function just calls a custom Dialog which is basically just the Flutter Dialog with some style changes.
Future<bool?> showDeleteDialog(BuildContext context,
{required String title, String? subTitle}) async {
return await showDialog(
context: context,
builder: (_) => DeleteDialog(title: title,subTitle: subTitle,)
);
}
In the dialog I press on a button and do this:
onPressed: () => Navigator.of(context).pop(true),
So looking at the first function I wait for my res which evaluates to true. At this point I thought the dialog should be popped. But it is not.
The problem is this call:
context.read().deleteEventRelatedData();
Because when I replace this call with e.g. Future.delayed(duration(seconds:5)); the dialog pops right away as expected.
This is the function:
Future<void> deleteEventRelatedData() async {
_ticketLoader.stop();
_ticketStorage.deleteScanTicketsForEvent(event.eventId);
_eventStorage.deleteEventPermissions(event.eventId);
_eventStorage.deleteEventData(event.eventId);
_ticketStorage.deleteCachedTicketsForEvent(event.eventId);
_ticketStorage.deleteCachedUnknownTicketsForEvent(event.eventId);
_ticketLoader.updateLastSync(null);
_ticketLoader.reset();
checkLocalStatus();
}
A function with some async and synchronous functions. The execution takes up to 3 seconds which is the time it takes to dismiss/pop my dialog. But I want to pop the dialog right away and let it work in the back. What could my function possibly do for this behavior?
Thanks in advance
The dialog window isn't going to disappear until the app can manage to do a rebuild. If your function call takes a while, it could be hogging the main thread until it's complete, disallowing other code (including widget code) from running.
Try wrapping your function call in a microtask so it doesn't run until the next available task window which will give the app time to clean up the dialog window:
await Future.microtask(deleteEventRelatedData);
It's also worth mentioning the body of the deleteEventRelatedData is marked as async but it never awaits anything. That means all of the synchronous calls can happen in a sequence that wasn't intended and the asynchronous calls won't get executed until a later time and in no guaranteed order.

Trying to use showDialog()/show Pop up on app startup

What I want to achieve: I want to open a pop up explaining my app when it starts.
My approach: As far as I understand it from googling the issue, I should use the showDialog() method. In its most basic form:
showDialog(
context: context,
builder: (context) {
return Text('data');
});
I tried returning actual dialogs (e.g. AlertDialog) but it doesn't change the behavior so I'm just using Text() with a string as a placeholder for now.
The problem:
No matter where I place the showDialog function, it doesn't work as intended (also see scrennshots below):
Placing it in initState: I get an error message about inherited Widgets being called before the initState is done + an explanation about dependiencies I can barely follow.
Placing it in the build method: I get an error message that setState() or markNeedsBuild() gets called while the app is already buildung widgets.
Placing it in DidChangeAppLifeCycleState(): This is actually working and opening the pop when I pause the app and then resume it. It is not opening on app startup though.
Wrapping it in WidgetsBinding.instance!.addPostFrameCallback(): An idea I picked up here: How to show a popup on app start in Flutter. Doesn't change the outcome of the error messages, neither in initState nor in build.
Any ideas?
Screenshots:
From initState:
From build method:
From DidChangeAppLifecycleState (the "succesful" variant:
Will you please try below code in your init method? I hope this may work.
Future.delayed(Duration.zero, () async {
myFunction();
});
Using WidgetsBinding.instance.addPostFrameCallback inside initState perform its inner task after the 1st frame is complete.
addPostFrameCallback Schedule a callback for the end of this frame.
Next issue arise for not having material. You can directly return AlertDialog on builder or wrap with any material widget like Material, Scaffold..
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text('data'),
);
},
);
});
}
If you are running version<3 null safety, use WidgetsBinding.instance?.addPostFrameCallback
One of the methods with WidgetsBinding.instance!.addPostFrameCallback() works fine .
If you show a normal show dialog with the press of a button too it will produce the same result.
Here, you need to wrap the text("data") in a dialog widget such as alertDialog or simpleDialog widget as needed and it will display the dialog within the current scaffold as -
WidgetsBinding.instance!.addPostFrameCallback((_) async {
return await showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text("data"),
);
});
});
I tried adding this in the init state and the dialog pops up fine when I restart the app
Thanks a lot for your answers. I ficed the issue by rewriting with your suggestions; and it works. I tihnk the issue was that I did not have _ or anything else in my WidgetsBinding code. So I did:
WidgetsBinding.instance?.addPostFrameCallback(() {})
instead of
WidgetsBinding.instance?.addPostFrameCallback((_) {})

Flutter: showing one dialog at a time

I am fairly new to state management in Flutter, and I have an application where the user will be interacting with dialogs, and a dialog may have a button to open another dialog which can result in the following:
https://i.stack.imgur.com/VBSzr.png
As shown, multiple issues arise when more than one is opened at once -- most notably the previous dialog is still visible in the background. So when a user opens a new dialog, is there any method where I can hide the dialog behind it, and when the frontmost dialog closes, show the previous one which is hidden? Thanks in advance.
Use Navigator.pop(context); method to close the dialog on your button's onPressed before opening the second dialog.
And then while closing your second dialog you can reopen your previous dialog.
Example:
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Hello World"),
content: Text("This is content"),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context); //Close your current dialog
//TODO:open your second dialog
},
child: Text("Open"))
],
);
});
I would first try to re-think the logic for opening multiple dialogs at the same time.
Maybe there is a quick workaround for that, but if you keep adding more and more dialogs, then it would become a mess.
Since showDialog<T> function returns Future<T?>, you could potentially use await and wait until the first dialog is closed and then open the second one and so on:
bool canContinue = await showDialog<bool>(
context: context,
builder: (context) => YourWidget(),
);
Alternatively, you could pop by using Navigator but as said, this will be visible to the user that something weird is going on (pushing and popping dialogs programatically).

Flutter - Alert Dialog showing multiple times inside listener

I am using a flutter_local_notifications to get a notification when a countdown timer has finished.
When i click the notification using onSelectNotification (callback of flutter_local_notification), I add a Subject (RxDart).
var selectNotificationSubject = PublishSubject<String>();
onSelectNotification: (String payload) async {
selectNotificationSubject.add(payload);
},
So the Subject is added successfully on the Stream.
I listen for the stream in initState. The AlertDialog is shown, but the problem is that it is shown multiple times for all the list with countdown timers.
I want to show the AlertDialog only for the timer that i clicked on the notification, not for all the timers that are available on the list.
A way to fix this may be to add to the AlertDialog widget a id so i can show it only once by the id of the countdown timer that is clicked on notification. Widget showDialogById()
subs = selectNotificationSubject.stream.listen((event) async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Repeat Timer ${timer.id}"),
content: Text(
"Do you want to repeat your timer ${timer.description} ?"),
actions: [
RaisedButton(
child: Text("Repeat"),
onPressed: () async {
//Repeat timer logic here
});
),
});
});
The way you coded it, it is expected to spam repeatedly to show the dialog.
If you don't want a new trigger dialog show, create a boolean to control it, whatever the bool is true it won't show, otherwise it will show

How to make Alert Dialog disappear after 30 seconds in Flutter?

So I am using an Alert Dialog in my project which should either be closed if the user clicks 'Ok' or 'Cancel' else it should disappear on its own after 30 seconds if the user gives no response. I was thinking of using setState and Duration or something like that but can't exactly figure out.
You can use Future.delayed to have a delayed action:
// dialog builder
showDialog(context, builder: (BuildContext context) {
bool manuallyClosed = false;
Future.delayed(Duration(seconds: 30)).then((_) {
if (!manuallyClosed) {
Navigator.of(context).pop());
}
});
// Build the dialog window
// Set manuallyClosed to true on the OK or Cancel button tap
});