Stuck at fetching a new question after a timeout (using Flutter) - flutter

I am building a Flutter Quiz app where the user gets a specific duration of time to answer the question. If the user fails to answer within the given time frame, the next question is retrieved.
The starttimer method acts as a counter and stops at 1.
void starttimer() {
_counter = 10;
if (_timer != null) {
_timer.cancel();
}
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
if (_counter > 0) {
print(_counter);
_counter--;
} else {
_timer.cancel();
}
if (_counter == 1) {
// TODO: nextQuestion();
}
});
});
}
The questions are in a list and a index is used to obtain a specific question within the Text widget ex: Text(questionlist[i]).
The nextQuestion() needs to increment the index by 1.
How can I achieve this? Or is there any other way to retrieve the next question?

Try this logic:
void startTimer() {
_counter = 10;
_timer?.cancel();
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
if (_counter == 0) {
nextQuestion();
timer.cancel();
}
_counter--;
});
});
}

Related

Flutter - Using Timer and .cancel() function

*** UPDATE ***
I have a problem. When I use a Timer in Flutter and cancel() it afterwards, but as soon the cancel method is triggered, nothing happens.
var counter = 0;
Timer.periodic(const Duration(milliseconds: 50), (timer) {
developer.log('Actual counter ' + counter.toString());
counter++;
if (counter == 5) {
developer.log('TIMER DONE');
timer.cancel();
}
});
developer.log('This comes afterwards');
Expected out put:
Actual counter 0
Actual counter 1
Actual counter 2
Actual counter 3
Actual counter 4
TIMER DONE
This comes afterwards
The Output:
Actual counter 0
Actual counter 1
Actual counter 2
Actual counter 3
Actual counter 4
TIMER DONE
normally I should see a message 'this is afterwards' in the console, but it seems that with the cancel the complete method will be canceled.
Many thanks in advance.
Update: perform operation end of timer.
You need to add logic inside if condition to perform operation.
if (counter == firmwareList.length) {
timer.cancel();
developer.log('This comes afterwards'); //here
}
});
Here is an widget example
class TimerF extends StatefulWidget {
const TimerF({super.key});
#override
State<TimerF> createState() => _TimerFState();
}
class _TimerFState extends State<TimerF> {
var counter = 0;
Timer? timer;
bool isTimerActive = true;
#override
void initState() {
super.initState();
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
print('Still timer');
if (counter == 5) {
timer.cancel();
isTimerActive = false;
}
counter++;
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text("current value ${counter}"),
if (timer?.isActive == false) Text("Timer isnt active"),
if (isTimerActive == false) Text("Timer isnt active $isTimerActive"),
],
),
);
}
}
I can't see any increment on counter on current snippet. that's why counter remains 0 and doesnt meet the condition to cancel the timer.
Perhaps it will be
var counter = 0;
Timer.periodic(const Duration(milliseconds: 50), (timer) {
print('Still timer');
if (counter == 5) {
timer.cancel();
}
counter++; //increment the value
print('this is afterwards');
});
Here is a fully working example using a Timer
Timer? timer;
startTimer() {
var counter = 0;
timer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
counter += 1;
print('Actual step $counter');
if(counter==5) {
cancelTimer();
}
});
}
cancelTimer() {
timer?.cancel();
print('this is afterwards');
//do something here
}
When you startTimer(), here is the output
Actual step 1
Actual step 2
Actual step 3
Actual step 4
Actual step 5
this is afterwards

Flutter How can I use setState and only change one area and leave the other as it is?

I want a page that has a timer and also displays math problems. and whenever the correct answer has been entered, a new task should appear. But the problem is that whenever a new task appears, the timer is reset. How can I prevent this ?
late Timer timer;
double value = 45;
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (value > 0) {
setState(() {
value--;
});
} else {
setState(() {
timer.cancel();
});
}
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
startTimer();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void userTextFieldInput() {
controller.addListener(
() {
String rightResult = (firstIntValue + secondIntValue).toString();
String userResult = controller.text;
if (rightResult == userResult) {
setState(() {
DatabaseHelper(
firstUserValue: firstIntValue,
secondUserValue: secondIntValue,
finalUserResult: int.parse(controller.text),
).setDB();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const CalculatePage(),
),
);
});
} else if (controller.text.length >= 2) {
controller.clear();
}
},
);
}
You should create two different state, one for timer and another one for the problems.
You can use the package flutter bloc to manage these state easily.

Flutter: I need help! My random icon pop up animations work but give errors when moving to next page

Map and icons
I have a map and I want to create icons that pop in and fade out after a few
seconds to show that there are other people in the area. These icons generate
random so I call set state to reset their locations, but I am getting errors
when a new page is built. These errors say that my controller was disposed and
then reverse was called and that the null check operator was used on a null
value.
Error Controller disposed then reverse called
Error null check operator used on a null value
Here is my code
late AnimationController _controller1;
late AnimationController _controller2;
late AnimationController _controller3;
Timer? timer1F;
Timer? timer1R;
Timer? timer2F;
Timer? timer2R;
Timer? timer3F;
Timer? timer3R;
#override
void initState() {
super.initState();
_controller1 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer1R = Timer(Duration(seconds: 10), () {
_controller1.reverse();
// print('1 Reverse');
timer1F = Timer(Duration(seconds: 30), () {
// setState(() {});
_controller1.forward(from: 0.0);
// print('1 forward');
});
});
}
}
});
_controller1.forward();
_controller2 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer2R = Timer(Duration(seconds: 20), () {
_controller2.reverse();
// print('2 Reverse');
timer2F = Timer(Duration(seconds: 20), () {
// setState(() {});
// print('2 forward');
_controller2.forward(from: 0.0);
});
});
}
}
});
// Future.delayed(Duration(seconds: 10), () {
// });
_controller2.forward();
_controller3 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer3R = Timer(Duration(seconds: 30), () {
_controller3.reverse();
// print('3 Reverse');
timer3F = Timer(Duration(seconds: 10), () {
// print('3 forward');
setState(() {});
_controller3.forward(from: 0.0);
});
});
}
}
});
_controller3.forward();
}
#override
void dispose() {
_controller1.dispose();
_controller2.dispose();
_controller3.dispose();
timer1F!.cancel();
timer1R!.cancel();
timer2F!.cancel();
timer2R!.cancel();
timer3F!.cancel();
timer3R!.cancel();
super.dispose();
}
Each controller is linked to a different icon, but the error is being called when I reverse the controller. It says it disposes first and then reverse is called. It also shows that if one of the controllers isn't initialized (due to the timer widget calling the controllers forward or reverse) then it gives me that null check assigned to null operator error.

setState() or markNeedsBuild() called during build. Trying to make a simple timer in flutter

I am trying to make a simple timer which run till a given time. This is how I have tried to call the timer function. It gives the error as mentioned in the title. I believe the error is there because I am calling set state method in the init state, but I really need to make this functionality that, when this widget enters the screen, a timer begins and do something when the timer ends. Any help is greatly appreciated.
late double timeRemaining;
late Timer _timer;
void startTimer(double timeRemaing) {}
#override
void initState() {
timeRemaining =
widget.startDate.difference(widget.endDate).inSeconds / 1000 - 80;
const Duration seconds = Duration(seconds: 1);
_timer = Timer.periodic(seconds, (timer) {
setState(() {
timeRemaining--;
if (timeRemaining <= 0) {
// done = true;
done = true;
timer.cancel();
}
});
});
super.initState();
}
as the title says, you're building widget during another build (when you call setState in the timer).So the solution is to wait for the widget to finish building, then start your timer, this can be done by using addPostFrameCallback, like the following:
#override
void initState() {
timeRemaining =
widget.startDate.difference(widget.endDate).inSeconds / 1000 - 80;
const Duration seconds = Duration(seconds: 1);
// this will schedule a callback for the end of this frame.
WidgetsBinding.instance.addPostFrameCallback((_) {
_timer = Timer.periodic(seconds, (timer) {
setState(() {
timeRemaining--;
if (timeRemaining <= 0) {
// done = true;
done = true;
timer.cancel();
}
});
});
});
super.initState();
}
try it and tell me if this works

Flutter How to make it vibrate on the last count?

I made a counter application, the user can determine the number of their own count. if the count reaches the count limit, I want it vibrate at the last count. For example, if I specify the number 5, the smartphone will vibrate on the 5th tap. However, I have a problem, because the vibration appears on the 6th tap.
How to make it vibrate on the 5th beat?
here is my code:
int _counter = 0;
int _five = 5;
onTap: () async {
setState(() {
if (_counter != _five) {
_counter++;
} else if (_counter == _five) {
Vibration.vibrate(duration: 500);
_counter = _counter + 0;
} else {}
});
},
Your code need a little change like:
onTap: () async {
setState(() {
if (_counter < _five) {
_counter++;
}
if (_counter == _five) {
Vibration.vibrate(duration: 500);
} else {}
});
}