So I ran into another problem with my timer.
I have a sized box, and when I tap on it I would want the timer to change the value from 5 minutes to 15 minutes (Or best, when I tap the first time it will increase from 5 minutes > 10 minutes on the second tap 15 minutes on the third tap to 20 minutes and on fourth to 25 minutes) For this to happen the timer should be not active(The user can only change it when the timer is not running) -- But I'm running into the problem of "Undefined name 'isRunning'." from my final in another widget
Here is my code (Also side question, currently the timer only displays seconds, how can I make it display the actual 5 minutes as in 5:00)
class timeryypage extends State<timerry> {
static const maxSeconds = 5;
int seconds = maxSeconds;
Timer? timer;
void resetTimer() => setState(() => seconds = maxSeconds);
void startTimer({bool reset = true}) {
if (reset) {
resetTimer();
}
timer = Timer.periodic(Duration(seconds: 1), (_) {
//add here instead seconds say minutes/miliseconds
if (!mounted) // Putting this line of code with return under, fixed my issue i been having about mounted
return;
else if (seconds > 0) {
setState(() => seconds--);
} else {
stopTimer(reset: false);
}
});
}
void stopTimer({bool reset = true}) {
if (reset == mounted) {
resetTimer();
}
setState(() => timer?.cancel());
}
@override
Widget buildButtons() {
final isRunning = timer == null ? false : timer!.isActive;
final isCompleted = seconds == maxSeconds || seconds == 0;
return isRunning || !isCompleted
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ButtonWidget(
text: isRunning ? "Pause" : "Resume",
onClicked: () {
if (isRunning) {
stopTimer(reset: false);
} else {
startTimer(reset: false);
}
},
),
const SizedBox(width: 12),
ButtonWidget(text: "Cancel", onClicked: stopTimer)
],
)
: ButtonWidget(
text: "Start Timer!",
color: Colors.black,
backgroundColor: Colors.white,
onClicked: () {
startTimer();
},
);
}
Widget buildTimer() => SizedBox(
width: 200,
height: 200,
child: Stack(
fit: StackFit.expand,
children: [
CircularProgressIndicator(
value: seconds / maxSeconds,
//if you delete 1 - then it goes to other direction
valueColor: AlwaysStoppedAnimation(Colors.white),
strokeWidth: 12,
backgroundColor: Colors.greenAccent,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (isRunning) {
print("do nothing");
} else {
const snackBar = SnackBar(content: Text('Tap'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
print("tapped");
// later on i want to change timer from 5 minutes 10 minutes on first tap, then second tap to 15 minutes
}
},
child: Center(child: buildTime()),
),
//Center(child: buildTime()),
],
),
);
Widget buildTime() {
if (seconds == 0) {
return Icon(Icons.done, color: Colors.greenAccent, size: 112);
} else {
return Text(
"$seconds",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 80,
),
);
}
}
Thank you so much for help!
Edit Adding extra code :
bool get isRunning => _timer?.isActive ?? false;
int _seconds = 00;
int _minutes = setminutes;
static const setminutes = 25;
Timer? _timer;
var f = NumberFormat("00");
void _stopTimer({bool reset = true}) {
if (reset == true) {
resetTimer();
}
setState(() => _timer?.cancel());
;
}
void resetTimer() => setState(() => _minutes = setminutes);
void _startTimer({bool reset = true}) {
if (reset) {
resetTimer();
}
if (_timer != null) {
_stopTimer();
}
if (_minutes > 0) {
_seconds = _minutes * 60;
}
if (_seconds > 60) {
_minutes = (_seconds / 60).floor();
_seconds -= (_minutes * 60);
}
_timer = Timer.periodic(Duration(seconds: 1), (_) {
if (!mounted)
return;
else if (_seconds > 0) {
setState(() => _seconds--);
}
setState(() {
if (_seconds > 0) {
_seconds--;
} else {
if (_minutes > 0) {
_seconds = 59;
_minutes--;
} else {
_stopTimer(reset: false);
}
}
});
});
}
@override
Widget buildButtons() {
//final isRunning = timer == null ? false : timer!.isActive;
final isCompleted = _minutes == setminutes || _seconds == 0;
return isRunning || !isCompleted
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ButtonWidget(
text: isRunning ? "Pause" : "Resume",
onClicked: () {
if (isRunning) {
_stopTimer(reset: false);
} else {
_startTimer(reset: false);
}
},
),
const SizedBox(width: 12),
ButtonWidget(
text: "Cancel",
onClicked: () {
_stopTimer(reset: true);
})
],
)
: ButtonWidget(
text: "Start Timer!",
color: Colors.black,
backgroundColor: Colors.white,
onClicked: () {
_startTimer();
},
);
}
CodePudding user response:
Your buildTime
function creates a Text
widget from the number of seconds. If you want to format it in some other way, you will need format the number of seconds to a String
yourself. For example:
var minutes = seconds ~/ 60;
var remainderSeconds = seconds % 60;
return Text('$minutes:${remainderSeconds.toString().padLeft(2, '0')}',
...);
Also see: