SetState in ternary operator - flutter

I want to change the color of the text displaying the scheduled time, if the scheduled time is past the current time then it should change to red and if its in the future then it wont change. This works properly but it only changes state when I click on another button. I am using a ternary operator like this:
color: (run(todoController.todos[index].date,
todoController.todos[index].time)
.compareTo(tz.TZDateTime.now(tz.local))>0)
? Theme.of(context).hintColor
: Colors.redAccent,
How do you add setState in a ternary operator? Thanks

I think the neater solution would be moving the logic of the comparison of time in a separate function which will be called each 2/5 second depending on your app. In that function, you can change the state and make sure to use color depending on the state.
The code for checking the future time each minute
var cron = new Cron();
cron.schedule(new Schedule.parse('*/3 * * * *'), () async {
if(run(todoController.todos[index].date,
todoController.todos[index].time)
.compareTo(tz.TZDateTime.now(tz.local))>0){
setState(() {
isFutureTime = true;
});
}
});
I have used corn. CORN documentation
Your Widget color code would look like this.
isFutureTime == false? Theme.of(context).hintColor : Colors.redAccent,
isFutureTime is the state boolean variable. You can follow this StackOverflow answer on changing the state periodically.

Related

How can I listen to a String variable change and perform an action when there is a change?

Is it possible to execute a function, lets call it myFunction() if a variable _myString is changed, but have this happen on the fly?
What I have is a textfield with a controller
var _myString;
const TextField(
controller:_controller
)
Now elsewhere in my widget tree, I have a button that can change the value of _myString, in this case I'm changing '_myString' to 'Testing'
GestureDetector(
onTap:(){ _myString = 'Testing'; }
child: Text('Testing')
)
Now what I'm hoping to achieve is that when the value of _myString changes in any way, I can perform some action of my choosing. In this case, I want to edit the TextField using the _controller, but I don't only want to do that, but a few other things, so I think its better to listen to changes in that variable and then execute a function
void myFunction(){
///Do some stuff
}
I'm using riverpod for state management in my app, and I was thinking I could try to use it, but have no idea how to use it to watch a single variable, I'm more familiar with using it for entire widgets. Alternatively using riverpod for something like this might be overkill.
I just don't know how to approach this problem, so any guidance would be really appreciated!
I believe you could use a ValueNotifier for this, a value notifier is a class that holds some value and "notifies" its listeners when this value changes. It is a simpler version of ChangeNotifier:
ValueNotifier<String> _myString = ValueNotifier<String>('');
With the above, whenever you want to read or write the value, use the value getter/setter:
print(_myString.value);
_myString.value = 'some value';
Now, to listen to changes you should use the addListener method:
#override
initState() {
// update _controller with value whenever _myString changes
_myString.addListener(() => _controller.text = _myString.value);
// print value on change
_myString.addListener(() => print(_myString.value));
// do stuff
_myString.addListener(myFunction)
}

Passing data to a previous screen

Firstly, if you pop a screen off, does it mean all initializations have been destroyed?
I initialized a few variables to a previous screen, was hoping to see the changes when I go back to the screen but I don't see the changes
Is it possible to pass a few data to a previous screen without moving to that screen? if yes, how?
Yes, it is possible.
You could do it in some variety of ways.
A simple way could be like that:
Having a private variable at the beginning of the method scope in a StatefulWidget
String _fileAvatarUpload = '';
Then, you would have your widget tree being displayed and a Widget you want to return a value to the tree:
Center(
child: ImagePickerSource(
isRunningWeb: kIsWeb,
image: _peopleModel.imageAvatar,
callback: callbackAvatar,
isAvatar: true,
imageQuality: 35,
),
),
In the callback method, you could use SetState to set the new value variable:
callbackAvatar(file, bytes) {
setState(() {
_fileAvatarUpload = file;
_bytesImgWeb = bytes;
});
}

Can a state in flutter call itself?

I have a stateful widget, that gets updated with button press events, is it viable to call the state from inside the same state on button press event? The states are a lot in number. So I want to avoid initializing too many states.
Yes you can call setState((){}) inside a StatefulWidget. According to the documentation:
Notify the framework that the internal state of this object has changed.
That means that, if you want to update any value on your StatefulWidget, make sure to call it inside the setState((){}), like this: setState(() { _myState = newValue; });
From what I understood, you don't want to have too many calls to the setState((){}) function. Since you are using a button, you can do it like this:
FlatButton(
child: Text("Tap me!"),
onPressed: () => setState((){ tapped = true}),
),
The arrows are syntatic sugar that substitute the curly brackets. Useful when there is only one line of code.

How to use Future<bool> in if statement condition?

In Flutter, am using "url_launcher" package which uses Future<bool> to check if the app can launch other apps. Within my code I have phone numbers listed, and I want to place an Icon for WhatsApp only if it is installed on the user's device.
bool hasWhatsApp() {
var whatsExists;
canLaunch('https://api.whatsapp.com/').then((val) => whatsExists = val);
return whatsExists;
}
am using this function to check inside an if statement to show the icon on the screen or not, however, it keeps returning 'null'.
if (phoneNumber.substring(0, 1) != '2' && hasWhatsApp())
IconButton(
icon: Image.asset('assets/icons/whatsapp.png'),
iconSize: Theme.of(context).iconTheme.size,
onPressed: () async {
await launch(whatsUrl);
},
),
how can I fix this please?
What you are trying to do cannot work.
Your function hasWhatsApp is synchronous, so it returns a value immediately when you call it.
Inside that function, you start an asynchronous computation, and when that computation finishes (at a later time), it overwrites a local variable. The function has long returned by then.
There is no way you can immediately return a value which is not available until later. It's simply not there.
So, you need to await the future so you can delay making the decision until the value is available.
For example, change your if to:
if (phoneNumber.substring(0, 1) != '2' &&
await canLaunch('https://api.whatsapp.com/')) {
...
}
That does mean that you have to make the function containing that if asynchronous.
I'm not a Flutter expert, I guess you might need to use a FutureBuilder.
There is no work-around for asynchrony.
You can await canLaunch method and convert your function as async. Since you make your function async, your return type needs to be Future Try this:
Future<bool> hasWhatsapp() async {
return await canLaunch('https://api.whatsapp.com/');
}
And if you use https://api.whatsapp.com/ as url it will always return true because it can launch it via browser. If you want to check if app is installed I guess you need to use canLaunch('whatsapp://') instead. Check https://stackoverflow.com/a/50672986/12709039 this answer for more

Flutter setstate() doesn't work with sleep()

I have a simple problem but I'm new to Flutter. I have to change the colors of 3 buttons, then wait 2 seconds and call another function.
This is the Code:
setState((){
clr[0]= 0==gst ? Colors.green:Colors.red;
clr[1]= 1==gst ? Colors.green:Colors.red;
clr[2]= 2==gst ? Colors.green:Colors.red;
});
sleep(const Duration(seconds:2));
cardKey.currentState.toggleCard(); // second function
The problem is that this code waits 2 seconds then change the colors and call the second function...
I tried also with the sleep() inside the setstate()
You should be using Future.delayed to solve your issues as sleep is not recommended. Make sure to define your function as async. However, if you don't want to mark as async (or the function doesn't work with async), you can use this:
Future.delayed(Duration(seconds: 2)).then((_) {
cardKey.currentState.toggleCard(); // second function
});
For more reading, I recommend this.