Perform two actions on the press of an IconButton - flutter

I am working on a music player, and on pressing next button I want to perform two functions one is to add song to the queue and another function is used to trigger the plugin method of 'addSong'. On button pressed I wish to execute two functions which are '_pageManager.addSong' and 'addSongToQueue'.
This is the code
ValueListenableBuilder<bool>(
valueListenable: _pageManager.isLastSongNotifier,
builder: (_, isLast, __) {
return IconButton(
icon: Icon(Icons.skip_next),
onPressed: (isLast)
? _pageManager.addSong
: _pageManager.onNextSongButtonPressed;
);
}),

I see your logic
I might suggest to create a function
void onAddSong() {
_pageManager.addSong();
// addSongToQueue()
}
Then call this
onPressed: (isLast)
? this.onAddSong
: _pageManager.onNextSongButtonPressed;
);
I'd suggest you to think in the scalability of this widget with that isLast #param, is it ok?

Don't use a ternary, and instead just use a function body.
onPressed: () {
function1();
function2();
}

You can use if in the oppressed function like this
onPressed: (){
if(isLast){
_pageManager.addSong
}else{
_pageManager.onNextSongButtonPressed;
}
}
or use it like this if you have to check only one condition
onPressed: () =>
isLast ? _pageManager.addSong
:
_pageManager.onNextSongButtonPressed;

Related

Flutter: Hide first alert dialog when other is shown

I want to hide the first alert dialog when I call showDialog() from it. After that when I close the second dialog I want the first dialog was visible again. How I can achieve this?
Before you call second dialog, use Navigator.of(context).pop() to close first dialog. Then, in the second one, you have functions then((value) {...}) or whenComplete(() {...}), inside that you can use it to re-open first dialog.
That's strange that you want to close first one, why don't you just leave it alone and let the second lies on it?
You can create common dialog to show data. if its already showing then just update data only.
showDialog return a future and you can pass data from dialog. The concept is here passing some flag to open the second dialog.
onPressed: () async {
final data = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: ElevatedButton(
onPressed: () {
Navigator.of(context)
.pop(true); // true for to show second dialog
},
child: Text("open Second dialog"),
),
);
});
if (data == true) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Second dialog"),
);
});
}
},

Flutter - Can only pop AlertDialog OR execute passed function - need to do both

TL;DR: Trying to pass a function call to a custom AlertDialog. AlertDialog needs to be popped after the function -> can't make it work.
I've created a custom AlertDialog to use throughout my app. It looks something like this:
customAlertDialog({required context, buttonAction}){
showDialog(context: context, builder: (context) => AlertDialog(
title: Text("example title", style: TextStyle(color: AppTheme.colors.white),),
content: const Text("some content"),
actions: [
TextButton(onPressed: () {Navigator.of(context).pop();}, child: Text(
"Abbrechen",
style: TextStyle(
color: AppTheme.colors.white),
),),
TextButton(
child: Text("do something",
style: TextStyle(
color: AppTheme.colors.lightRed),
),
onPressed: buttonAction)
],
),);
}
The customAlertDialog takes a function call as an argument (here named buttonAction) for the last TextButtons onPressed action. It works fine when I pass:
buttonAction: () => deleteUser(context)
The problem is that this does not work in combination with a pop method. In the following only deleteUser will be called:
buttonAction: () => [deleteUser(context), Navigator.of(context).pop()]
the same if written like this:
buttonAction: () {deleteUser(context), Navigator.of(context).pop()}
I guess that the context of the customAlertDialog itself needs to be popped. So I've tried the following in the customAlertDialog (buttonAction contains () => deleteUser(context):
onPressed: () => [buttonAction, Navigator.of(context).pop()]
Now it only pops the dialog, probably because dart cannot interpret the buttonAction. So I've searched to find a way to pass only the function that should be called but wasn't successful doing so.
So my question is: How can I pass a function and still pop the dialog?
EDIT:
As #SlowDeepCoder mentioned the problem could have been that the Navigator.pop() method throws the context from the stack before deleteUser() has finished and therefore it doesn't work. It was tried to be fixed with the following but it did not work:
buttonAction: () async{ await deleteUser(context); Navigator.of(context).pop(); }
This is because you call pop() on a Navigator from an incorrect BuildContext. So instead of
buttonAction: () {
deleteUser(context);
Navigator.of(context).pop();
}
you have to do something like this:
buttonAction: (innerContext) {
deleteUser(innerContext); // not sure if you need the innerContext here. Depends on your other app code
// deleteUser(context); // use this line if the above does not work
Navigator.of(innerContext).pop();
}
together with
TextButton(
child: Text("do something"),
onPressed: () => buttonAction(context),
)
I also would recommend you to give bot of your BuildContexts (customAlertDialog and showDialog) different names.
You do not always have to use arrow function to pass a custom function.
You can simply pass the function as
buttonAction: (){
deleteUser(context);
Navigator.of(context).pop();
}

Create dynamic return depending on logic behind in dart?

I am a beginner at dart/flutter. Is it possible to create a function or ... like this in dart? Seriously, I don't know what it is called! Let me explain what I wanted. Let say my app have 2 account type "premium" & "free". I want to create a widget or callback function or whatever which can return Type depending on my app account type (this calculated in underlying):
- Use in widget
Container(
child: AccountType.when(
(premium) => PremiumWidget(),
(free) => FreeWidget(),
),
),
For checking account type is done in underlying.
- Use in function
IconButton(
onPressed: AccountType.when(
(premium) => () {},
(free) => () {}
),
icon: Icon(Icons.ac_unit),
),
How can I achieve that? Any help would be appreciated. Thank you
You can use enum and if/else for that. First create the AccountType enum:
enum AccountType {
premium,
free,
}
Usage in widget:
Container(
child: (accountType == AccountType.premium ?
PremiumWidget() :
FreeWidget())
);
Usage in function:
IconButton(
onPressed: () {
if (accountType == AccountType.premium) {
// do something for premium account
} else {
// do something for free account
}
},
icon: Icon(Icons.ac_unit),
);

How to put two conditions in the Onpressed FlatButton?

I tried to put two conditions with the values of an email and a password in order to activate my button only if the two conditions are validated but it is not working because I think my syntax is written in a bad way.
Can you help me to resolve this problem please ?
Plus I have no error messages except the fact that the button doesn't navigate to the HomePage like it lost its fonction.
This is my code
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14, horizontal: 40),
color: DarkTurquoise,
onPressed: _password.length < 6 ? null :() {
!emailRegex.hasMatch(_email) ? null : () {
if (_formKey.currentState!.validate()) {
print(_email);
print(_password);
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
);
};
},
If you need to validate two conditions same time, use '&&' operator.
_password.length < 6 && !emailRegex.hasMatch(_email) ? <do something> : <do someting>
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14, horizontal: 40),
color: DarkTurquoise,
onPressed: _password.length < 6 && !emailRegex.hasMatch(_email) ? null : () {
if (_formKey.currentState!.validate()) {
print(_email);
print(_password);
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
);
},
),
use this:
onPressed: ()=>{
if (_formKey.currentState!.validate()) {
if(_password.length >= 6 && emailRegex.hasMatch(_email)){
// put your code here!
}
}
}
In flutter, if you want a button to be greyed out or not clickable, you give null to onPressed, which is what is happening in your case based on the condition saying if password < 6.
What happens is when the widget is build, it reaches the line of onPressed, applies the condition you gave it, and it discovers that indeed the password is <6, because no characters have been entered yet.
The widget is built now, and what is done is done.
After you start entering letters, the length becomes longer than 6, but the widget has already been built and you didn't trigger your UI to update and rebuild the button.
What you can do, is to move the null inside your logic, this will not grey out the button, but when you tap it and the conditions fails, nothing happens, like this:
onPressed: () {
if( _password.length >= 6) {
if(emailRegex.hasMatch(_email)){
if (_formKey.currentState!.validate()) {
print(_email);
print(_password);
//I moved the curly brace which was here to the end of the function,
//because I think you only want to navigate if the validation is true, not whenever it is pressed.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),),
);
};
}, //<= new curly brace
}
This is not the right way.
Textfield validation in Flutter
Hope you can get your answer by referring to this article.
Also you can make one function for check password length and like that and create bool true or false and that bool is useful for enable and disable button as well.

Flutter pop best practice

I have the following flow Screen 1 -> Screen 2 -> Dialog (in a separate widget).
Screen 2 displays a dialog (Close? Yes or No). If someone presses Yes, I would like to return to the Screen 1, if they press No, just close the dialog and return to Screen 2. What I currently do is when Yes is tapped, I do Navigator.pop(context) twice. Is this a good practice? Is there a way to pass the context of Screen 2 to my dialog widget so I can pop that one directly?
Personally, I think it would be better to pass the response from the dialog back to the page, and let the page handle the rest.
You can do this:
//I'm using a raised button just to call the alert as an example...
RaisedButton(
child: Text('Press me'),
//This part here is the important part
onPressed: () async {
//You can return anything when you use Navigator.pop
//In this case I'm returning a bool indicating if the page should close or not.
//You have to await this because it depends on user input.
bool shouldPopResult = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
//The content of your dialog
actions: <Widget>[
// The value you pass here in Navigator.of(context).pop
// is the value that will be stored in shouldPopResult,
// so if "Yes" is pressed, true will return...
// and if "No", false is returned.
FlatButton(
child: Text('Yes'),
onPressed: () => Navigator.of(context).pop(true),
),
FlatButton(
child: Text('No'),
onPressed: () => Navigator.of(context).pop(false),
)
],
),
);
// This is for if the user dismisses the dialog without pressing a button
// In that case shouldPopResult would be null, so I'm setting it to false.
// You can prevent the user from dismissing the dialog
// setting barrierDismissible to false in the showDialog method.
if (shouldPopResult == null) shouldPopResult = false;
// And finally with the dialog already dismissed, you can decide
// to go back or not.
if (shouldPopResult) Navigator.of(context).pop();
});
As usual you can extract the dialog as a Widget, or extract the function that handles the dialog response altogether or anything else.
You can see the example of returning data from a page in the flutter documentation here.