adding as favorite conditionally in Flutter - flutter

I am using the favorite_button Widget to add items to the list of favorites.
For that matter, I have a listview and for each row, I added the option to add it as a favorite. I also have a condition in the backend that if the number of favorites is more than 10, the responsecode equals to 2 and then shows a dialogbox in the flutter and does not add it to the favorite.
Everything works perfectly. The only problem that I have is that in conditions with more than 10 favorites, when I click, it marks as favorite and then shows the dialog box but I could not find a way to undo this action. However, it does not add it to the list (when I refresh the page, it shows as unmarked). How could I unmark it from marked as favorite, for example, when user closes the showDialog?
Any other approach is also appreciated like simulating the onpressed action to undo the action of favoriting.
Thank you in advance.
StarButton(
isStarred: UserFavorite
.Users!
valueChanged: (_isStarred) {
if (_isStarred == true)
setState(() async {
var resp =
await add(
widget.oauth,
widget.Id,);
if (resp.responseCode ==
2) {
await showDialog(
context: context,
builder:
(alertDialogContext) {
return AlertDialog(
title: Text(
'Limit Reached'),
content: Text(
'You are allowed to add up to 10 sensors as your favorite.'),
actions: [
TextButton(
child: Text(
'Ok'),
onPressed:
() {
Navigator.pop(
alertDialogContext);
},
),
],
);
},
);
}
});
else
setState(() {
delete(
widget.oauth,
widget.Id,
);
});
},
)

Related

Flutter DropdownButtonFormField not updating

I have an 'Add' link in my dropdown, which navigates to a form to do an add, and then sets the state afterwards, adding the new item to the dropdown. At least that's the way it was working; I tried to refactor to reuse this dropdown (it has some logic attached to it), and it no longer works...
Before, working:
The dropdown was added in a single stateful widget, and this code set the state:
TextButton(
child: Text(linkText),
onPressed: () {
Navigator.pop(aidingDropdownKey.currentContext!);
Navigator.push(context,
MaterialPageRoute(builder: (context) => linkDest))
.then((_) => setState(() {}));
},
)
Now, the dropdown is in its own StatefulWidget, and the DropdownMenuItem with the 'Add' link is in its own class. The code that tries to set the state looks like this:
TextButton(
child: Text(text),
onPressed: () {
if (poppee != null) {
Navigator.pop(poppee);
}
Navigator.push(context,
MaterialPageRoute(builder: (context) => dest))
.then((_) {
var afterClosed = afterLinkClosed;
if (afterClosed != null) {
afterClosed();
}
});
},
)
and
DropdownLabel(
"NTRIP Services",
linkText: "Add",
linkDest: const NtripForm(),
linkPoppee: widget.aidingKey?.currentContext,
afterLinkClosed: () {
_logger.d("after link callback called");
setState(() {});
},
)
Through logging, I can see my dropdown's build method is getting called, and the new menu item is created, but the UI isn't updating; the new item isn't showing.
Why wouldn't the UI update in this case?

how to navigate to another page at else statement in flutter

I have a List of String stored in a variable like this:
var question = [
'whats your favorite name',
'whats your favorite color',
'whats your favorite shape',
];
And have function that increase a variable each time I call it
void _Press(){
setState((){
_PressedNo = _PressedNo + 1;
});
print(_PressedNo );
}
And in my scaffold iam checking if the _PressedNo is smaller that List so it rebuild the scaffold with the new question each time i press the button till the questions finished like this :
return MaterialApp(
home: Scaffold(
body:_PressedNo < question.length ? Container(
child: RaisedButton(
child: Text('yes'),
onPressed:() {
_Press();
},
),
) : // here i want to go to another page
And after the else : i want to go to another Flutter page, but I can only add widgets here so any solution how to do that..
You'll have to take a bit of a different approach. The build method should only provide things that appear on the screen and not directly trigger a specific action or state change, such as navigating to another page.
You can handle this in the _Press() method:
void _Press() {
if(_PressedNo < questions.length) {
setState(() {
_PressedNo = _PressedNo + 1;
});
} else {
Navigator.of(context).push(...); // navigate to another page
// optionally set the _PressedNo back to 0
setState(() {
_PressedNo = 0;
});
}
}
Your build method should not change, since on this page it should always show the same button.
return MaterialApp(
home: Scaffold(
body: Container(
child: RaisedButton(
child: Text('yes'),
onPressed:() {
_Press();
},
),
),
);
Some other pointers:
use lowerCase for functions and variables: _press() and _pressedNo.
You can directly pass in the function to onPressed like onPressed: _press, (note that there are no parentheses since the function is not called but just passed along)

How stop SetState flutter

I work on flutter project . when i click to modify icon to edit name for example ==> the screen is roaleded automatically . How i can stop refresh screen after click on edit button ?
this piece of my Form code :
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Adresse email :',
style: TextStyle(
color: Color(0xFF4053FCF),
fontSize: 16,
fontWeight: FontWeight.w600
),
),
IconButton(
icon: Icon(CommunityMaterialIcons.pencil,
color: Colors.grey,
),
onPressed: () {
emailNode.requestFocus();
setState(() {
enableemail = true;
});
})
],
),
void editUserProfile() async {
setState(() {});
// if (_formKey.currentState.validate()) {
String name = _nameController.text;
String email = _emailController.text;
String adress = _adressController.text;
userApi.editUserProfile(name, email, adress).then((data) {
print(data);
if (data != null) {
// Navigator.pop(context);
/* Navigator.push(
context, MaterialPageRoute(builder: (context) => Profile()));*/
}
// setState(() {});
/* Navigator.push(
context, MaterialPageRoute(builder: (context) => BoxSettings()));*/
setState(() {
enableup = false;
enableadress = false;
enableemail = false;
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(data)));
// ScaffoldMessenger.of(context).showSnackBar(snackBar3);
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {});
}
and this my screen for more information :
How i can press on edit button without reload screen ?
There some workarounds to achieve this (i.e. update the state of one widget after tapping a completely different widget) like passing the callback function as a parameter etc.
But The best and neat solution here which will solve the above problem and keep your code neat is using Provider pattern.
If you are not aware of how a Provider pattern works, you can easily google search for articles regarding it. Here is one of them :
https://www.raywenderlich.com/6373413-state-management-with-provider
Read the above article before moving below.
Basically what we do is :
Create a ChangeNotifier class.
Wrap the parent of both widgets by a ChangeNotifierProvider widget.
Wrap the widget you want to update with Consumer widget.
Then in your onTap/onPressed function of Edit button you can call a function which will call the notifyListener() function. What this will do is it will notify the above ChangeNotifierProvider widget that some change has neen occured in it's widget tree. Then it will traverse the child whole widget tree below and will update the widget wrapped with Consumer widget.
So this way, you wont need to refresh your whole screen and you can easily update one widget by doing some action on a competely different widget.
Wrap the widgets you want to refresh inside stateful builder and make the whole screen a stateless widget and then call stateful builder

Closing ModalBottomSeet before time on Flutter causes black screen

I'm trying to create a modal bottom sheet using showModalBottomSheet, which wil display a form to register a todo item. The idea is that once the todo item is registered, I want to display a check icon from some seconds and then automatically close the sheet.
here is the snippet:
FloatingActionButton _floatingActionButton(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
await _showBottomSheet(
context: context,
content: CreateTodoForm(
onClose: () {
...
Navigator.pop(context);
},
),
);
},
);
}
and inside the CreateTodoForm widget:
class _CreateTodoFormState extends State<CreateTodoForm> {
TextEditingController titleController = TextEditingController();
bool completed = false;
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => getIt<TodoFormBloc>(),
child: BlocBuilder<TodoFormBloc, ITodoFormState>(
builder: (context, state) {
...
if (state is SubmittedTodo) {
Future.delayed(Duration(seconds: 2), widget.onClose);
return Container(
height: 127,
child: Icon(Icons.check, size: 50, color: Colors.white),
);
}
...
},
),
);
}
Has you can see, when the state is SubmittedTodo (todo was submitted successfully) I return a container with the check icon, and after 2 seconds I call the onClose Function which is a call to Navigator.pop(context) to close the sheet.
This works great but it has a problem... if the user taps the < button on the device, or swipe the sheet down to dismiss it, before the 2 seconds are completed, then the sheet closes due to the user action, and then the future completes and it basically closes the app (the app get full black screen).
So my quiestion is how can I close the sheet automatically after some time safely without worring about what the user does.
Probably this is happening because of Navigator.pop(context); getting called after you click the back button which cause two pop. and the black screen is shown because there is no other screen to navigate back to.
As a solution i propose wrapping your form widget by WillPopScope and then you will get notified that the user clicked on the back button. here you can close your form by calling onClose

Flutter buttons not hiding on first click

I am writing a flutter application and in it, I have join/leave event buttons when the stream comes in it sets the button to either true or false, eg: if a user is in the event it is set to true so the leave button shows up but when I click the leave button I have to click it twice to change before it changes back to the join button when I print the value i can see it change back to true the first click but the UI doesn't change the button back until the second click does anyone know why this is
child: eventStatus
? FlatButton(
child: Text('Leave Event'),
color: Colors.redAccent,
onPressed: () async {
int st = int.parse(eventData.votes);
int newVotes = --st;
await DatabaseService.instance.removeVote(
AuthService.instance.user.uid,
newVotes.toString(),
this.widget.event);
_snackbar.showSnackBarSuccess('OK LEAVE THEN !');
setState(() {
eventStatus = !eventStatus;
print(eventStatus);
});
})
: FlatButton(
child: Text('Join event'),
color: Colors.greenAccent,
onPressed: () async {
int st = int.parse(eventData.votes);
int newVotes = ++st;
await DatabaseService.instance
.vote(newVotes.toString(), this.widget.event);
_snackbar.showSnackBarSuccess('Hey you have friends !');
setState(() {
eventStatus = !eventStatus;
print(eventStatus);
});
}),
Use async/await in other function with Future, and call it in onPressed