making the gif start from the begining after closing and reopening it - flutter

I am trying to make this gif appears when clicking on the floating action button and popint it again after pressing on ok:
https://66.media.tumblr.com/1ce23970665b7736bd857720ebf5a5b2/tumblr_pp3sftPVIy1wb1n5x_540.gif
The problem is that when I click ok and reclick the floating action button, the gif continue from it stopped last time I pressed ok; I want it to start from the begining every time I click the floating action button. How can I do this? Here's the code:
floatingActionButton: FloatingActionButton(
child: Icon(Icons.healing),
onPressed: () {
showDialog(
context: context,
builder: (_) => Container(
height: 200.0,
child: NetworkGiffyDialog(
// key: keys[1],
image: Image.network(
gif,
fit: BoxFit.fitHeight,
),
title: Text("Exercises of breathing"),
description: Text(
'This will help you with breathing exercises to overcome anxiety attacks',
),
entryAnimation: EntryAnimation.RIGHT,
onOkButtonPressed: () {
Navigator.of(context).pop();
},
),
),
);
},
//child: new Text("Breathing exercise"),
),
EDIT: I followed the first answer and tried to switch between null value and the gif link as follows, however i still have the same problem
floatingActionButton: FloatingActionButton(
child: Icon(Icons.healing),
onPressed: () {
setState(() => gif = giflink);
showDialog(
context: context,
builder: (_) => Container(
height: 200.0,
child: NetworkGiffyDialog(
// key: keys[1],
image: Image.network(
gif,
fit: BoxFit.fitHeight,
),
title: Text("Exercises of breathing"),
description: Text(
'This will help you with breathing exercises to overcome anxiety attacks',
),
entryAnimation: EntryAnimation.RIGHT,
onOkButtonPressed: () {
Navigator.of(context).pop();
setState(() => gif = null);
},
),
),
);
},
//child: new Text("Breathing exercise"),
),

One thing you can try is using your variable gif as setState a null value to it after the animation (GIF duration) ends (or if user cancels).
var gif = "https://theurlofyourgif.com/file.gif"
void doYourGIFLogic() {
// show it with a Navigator, or Opacity, or Visibility, etc
// wait for that animation (GIF duration) to be done
final NetworkImage provider = NetworkImage(gif);
provider.evict().then<void>((bool success) {
if (success) {
print('removed image!');
}
});
}
When the user clicks again using the FAB, the cache will be cleared and the GIF should start from the beginning.

Related

How to pop out double alert message

I am new to Flutter. I made my first pop out confirmation alert dialog (Figure 1) but I want to pop another alert dialog window after.
What I am trying to achieve, it's the following: after I click Yes (Figure 2) the app would lead me to my homescreen and pop out another alert dialog.
You could create a method for the second Alert to show up, and call it when you click "YES" on the first one.
void showSecond(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text("Thank you for paying with us"),
content: Icon(Icons.check_circle_outline),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Okay'),
),
],
),
);
}
and your onPressed() of "YES" in the first alert should look something like:
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const SuccessPay()));
showSecond(context);
},
It was a bit hard to replicate your code from an image, so if something it's not accurate let me now. For the next time, post your code in a code block instead of a picture :)
you can call showAlertDialog to show second popup.(you can create new method to show second popup as content is different)This line can be added after
Navigator.of(context).pop() of first popup
You can use the .then() method. Call it if the user pressed the "YES" button.
Add value when poping your dialog like this Navigator.of(dialogCtx).pop(true);
showDialog(
context: context,
builder: (dialogCtx) => AlertDialog(
// title:
// content:
),
actions: [
TextButton(
onPressed: () {
Navigator.of(dialogCtx).pop(false);
},
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.of(dialogCtx).pop(true);
},
child: const Text('YES'),
),
],
),
).then(
(value) => {
if (value == true)
{
// display the next dialog with the scaffolds context
},
},
);

Flutter FlushBar does not work if I have to pre-process data

I am trying to build a form in Flutter. A user enters a value and clicks on a button, I run some basic validation on that value then show an AlertDialogue as a confirmation. If the user clicks on confirm I want to attempt an API call, get the result and display the result of that API call to let the user know what happened.If I display a Flushbar with hardcoded values it works. But If I try to do some string manipulation on the object first the Flushbar does not display. If I try to print the response from the function right into the Flushbar that also does not work.
Any advice on why this problem is occurring in the first place, and what would be the best way to solve it?
Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
textStyle: TextStyle(
fontSize: 30,
),
primary: Colors.lightGreen, // background
onPrimary: Colors.white, // foreground
),
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate())
{
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Confirmation'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('Please confirm your action'),
Text('Would you like to buy ' + finalValue.toString() + ' worth of merchandise'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('Confirm'),
onPressed: () {
Navigator.of(context).pop();
var response = bb.trade(_character, finalValue, true); //API CALL
*//String resp = response.body.split(',')[1].split(':')[1];
//resp = resp.substring(1);
//resp = resp.split('.')[0];
//print(resp);* //The real string manipulation we want to do but then flushbar does not display
Flushbar(
title: "Result",
message: "lol"+response.body.toString(), //FLUSHBAR DOES NOT DISPLAY AT ALL
duration: Duration(seconds: 5),
)..show(context);
},
),
],
);
},
);
}
},
child: Text('Buy'),
),
),
I Think the problem is that you are trying to access data from API call immediately , however data coming over API call must be awaited for.
and it is preferred to pop after showing the flush bar .
so if bb.trade(_character, finalValue, true); return future you should do like this
onPressed: () async {
var response = await bb.trade(_character, finalValue, true);
Flushbar(
title: "Result",
message: "lol"+response.body.toString(),
duration: Duration(seconds: 5),
)..show(context).then((value) => Navigator.pop(context));
},

Flutter Dynamic PopupMenu Content

I'm trying to create a menu that has a 'load more' functionality. From an interface perspective, PopupMenuButton has worked nicely, but I've been unable to dynamically refresh its content.
I'm using redux and I can successfully dispatch the action to fetch more, and the store is updated, but I don't see the change until I close the menu and re-open it, despite wrapping the PopupMenuButton in a StoreConnector. I also have a check for fetchInProgress that should be changing the bottom 'more' item to a spinner while the fetch is in progress, but that state change isn't noticed either.
I'm relatively new to Flutter so I'm wondering if I'm missing something.
Gif of the behavior
#override
Widget build(BuildContext context) {
return StoreConnector<AppState, _ViewModel>(
converter: (store) => _ViewModel.fromStore(store, oneOnOneId),
builder: (ctx, vm) => PopupMenuButton(
onSelected: (callback) => callback(),
icon: Icon(Icons.expand_more),
itemBuilder: (_) =>
[...vm.pastOneOnOnes.map((m) {
return PopupMenuItem(
child: Center(child: Text(DateFormat('MM/dd/yyyy').format(m.meetingDate))),
value: () => {
Navigator.of(context).pushReplacementNamed(routeName,
arguments: {
'meetingId': m.id
})
}
);
}).toList(),
PopupMenuItem(
enabled: false,
child: Container(
height: 40,
width: double.infinity,
child: vm.fetchInProgress ?
Center(child: CircularProgressIndicator()) :
InkWell(
onTap: () => vm.fetchPastOneOnOnes(oneOnOneId, start: vm.pastOneOnOnes.length + 1),
child: Center(
child: Text('More', style: TextStyle(color: Colors.black))
)
),
),
value: null
)
]
),
);
}
}
You need to update the state when you make a change. When you call => vm.fetchPastOneOnOnes wrap it with setState :
onTap: () {
setState(){
vm.fetchPastOneOnOnes(...);}},

Run a function AFTER that the alertbox has been dismissed

I already read countless links like this one but it does not help.
The use case is very simple, I want to run a function AFTER the alert box has been dismissed.
void dummyFunc() {
sleep(Duration(seconds:3));
print("done");
}
Future<bool> displayDialog() async {
return showDialog<bool>(
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('Decline'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
FlatButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
elevation: 24.0,
shape:RoundedRectangleBorder(),
);
},
);
}
var button = AnimatedOpacity(
opacity: 1.0,
duration: Duration(milliseconds: 500),
child: FloatingActionButton(
tooltip: 'Start',
child: Icon(iconShape),
onPressed: () async {
bool shouldUpdate = await displayDialog();
print(shouldUpdate);
if (shouldUpdate)
dummyFunc();
})
);
But the alert dialog is dismissed 3sd after.
Kindly let me know what I am doing wrong, Thank you~
I think this is happening because you are using sleep. Instead of that use Future delay.
void dummyFunc() {
print("done");
}
If you don't want delay, then you can also remove this future, this function will executed after dialog box dismissed.
Sleep will hold the process, that’s why you are facing this error.
Solved it thanks to Viren who gave me a good intuition, Timer works also nicely if you are not using a loop:
void dummyFunc() {
Timer(Duration(seconds: 3), () {
print("done");
});
}
Edit: Actually Viren's answer work better with loops! This can work also. Just avoid sleep. Spent 3h on this, now I hate sleep().

The dialog box opens multiples time at a same time in flutter

whenever I click many times on wheel, open multiple dialog boxes at the same time.
I just want, it should be open after previous got dismissed.
I took an image and add animation on it and wrapped it with GestureDetector widget.
onTap: event i called alertDialogBox() method which is defined for Dialog box. watch above the gif image, and called the animation method with specific Condition
CODE:
Dialog box
alertDialogBox(BuildContext context) {
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0))),
contentPadding: EdgeInsets.only(top: 10.0),
content: Stack(
children: <Widget>[
....
],
),
);
});
}
The Wheel:
GestureDetector(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
child: new AnimatedBuilder(
animation: _animationCtrl,
child: Container(
height:MediaQuery.of(context).size.height/2.3,
width: MediaQuery.of(context).size.width/1.3,
decoration: BoxDecoration(
color: Colors.blue,
image: DecorationImage(
image: AssetImage('assets/wheel.png', ),
fit: BoxFit.contain,
),
borderRadius: BorderRadius.all(Radius.circular(130.0)),
)
),
builder: (BuildContext context, Widget _widget) {
.......
},
),
),
onTap: ()async{
await Firestore.instance.collection('Users').document(uid).get().then((DocumentSnapshot documnet){
getIsSpin=documnet['isSpin'];
});
if(getIsSpin=="0"){
if (!_animationCtrl.isAnimating) {
//applying animation
}
DateTime now = DateTime.now();
// String lastSpinTime =DateFormat("yyyy-MM-dd hh:mm:ss").format(now);
.....//here updating isSpin value=1 and also updating spining Date time to firestore
}else {
oneDayDuration();
}
}
)
After 24 hours trying to spin the wheel
oneDayDuration():
void oneDayDuration()async{
int differenceTime;
await({
....here fetching last spin date time from firestore});
....//here getting difference hours between last spining time and current time
if(differenceTime>=24){
await({......//updating ispin=0 to firbase
})
.then((result) => {
print("Now you're able to spin"),
}).catchError((err) => print(err));
}else{
print("Please wait for 24 hours");
alertDialogBox(context);
}
}
}
Maybe this is because, you are trying to show dialog Asynchronously, where you don't have to. Just remove async, it is unnecessary while showing a simple dialog.
You better create a method that runs async in the if condition, and remove async in the onTap. This will separate your dialog code with async.
It is too late to answer this question, I came across the same scenario and solved it.
This is because the alertDialogBox function is invoked by build method every time the state is changed. you need to limit it by adding a variable to class like 'isAlertboxOpened' and make opening of alertDialogBox conditional and avoid opening multiple dialog boxes.
The following code should work
class _MyHomePageState extends State<MyHomePage> {
bool isAlertboxOpened; // add this
#override
void initState(){
isAlertboxOpened = false; // add this
}
alertDialogBox(BuildContext context) async {
setState(() => isAlertboxOpened = true); // add this
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0))),
contentPadding: EdgeInsets.only(top: 10.0),
content: Stack(
children: <Widget>[
....
// when press ok button on pressed add this
onPressed:(){
// your code
setState(() => isAlertboxOpened = false);
Navigator.of(context).pop();
}
],
),
);
});
}
void oneDayDuration()async{
int differenceTime;
await({
....here fetching last spin date time from firestore});
....//here getting difference hours between last spining time and current time
if(differenceTime>=24){
await({......//updating ispin=0 to firbase
})
.then((result) => {
print("Now you're able to spin"),
}).catchError((err) => print(err));
}else{
print("Please wait for 24 hours");
isAlertboxOpened ? (){} : // add this to make this conditional
alertDialogBox(context);
}
}
}