Flutter - Handling Life Cycle - flutter

Thanks for reading my question.
I wonder why
Unhandled Exception: setState() called after
dispose():_PomodoroState#42b6e(lifecycle state: defunct, not mounted)
is occured when I leave that page without pausing my timer function!
and also I want to know if it's fine to leave it like this.
But I think it's not good idea so I want some advices from you guys
This is my timer code.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cat_app/provider/counts.dart';
class Pomodoro extends StatefulWidget {
#override
_PomodoroState createState() => _PomodoroState();
}
class _PomodoroState extends State<Pomodoro> {
double coinCount = 0;
Stopwatch watch = Stopwatch();
late Timer timer;
bool startStop = true;
String elapsedTime = '';
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
print("startstop Inside=$startStop");
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
});
if (coinCount == 360000) {
context.read<Counts>().add(1);
coinCount = 0;
} else {
coinCount = coinCount + 10;
}
context.read<Times>().timeAdd(100);
}
}
restartTimer() {
updateTime(timer).cancel();
setState(() {
startStop = true;
watch.stop();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Container(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(elapsedTime,
style: TextStyle(fontFamily: 'Kitto', fontSize: 25.0)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onPressed: () => startOrStop(),
icon: Image.asset('assets/button.png'),
iconSize: 50,
)
],
)
],
),
),
);
}
startOrStop() {
if (startStop) {
startWatch();
} else {
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
int hours = (minutes / 60).truncate();
String hoursStr = (hours % 60).toString().padLeft(2, '0');
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$hoursStr:$minutesStr:$secondsStr";
}
}
Can you tell me what is wrong?? I want to handle it!

dispose() is used to execute code when the screen is disposed. Equal to onDestroy() of Android.
Example:
#override
void dispose() {
anyController?.dispose();
timer.cancel();
super.dispose();
}
Add this in your Code

Related

How can I stop Timer period in Flutter?

class _LiftButtonLayerState extends State<LiftButtonLayer> {
late Timer _timer;
late double _timeElapsed;
var isPause = false;
var isTrue = true;
#override
void initState() {
super.initState();
}
repeatDownActivate() {
_timeElapsed = 0;
final timer = Timer.periodic(Duration(milliseconds: 200), (timer) {
liftDownButton.postReq();
print("down singal 5per 1 second ");
});
}
Container(
width: 180,
height: 60,
child: GFButton(
onPressed: () {
repeatUpActivate();
print('clicked Up Button');
},
text: '▲',
textStyle: const TextStyle(
fontSize: 26,
color: GFColors.WHITE,
),
shape: GFButtonShape.pills,
size: GFSize.LARGE,
buttonBoxShadow: true,
)),
I found out that I can use Timer.cancel() from Flutter's Timer library.
I made a function for timer.cancel() , and applied timer.cancel() to onPressed on the new other button, but it doesn't work.
repeatUpActivate(isTrue) {
if (isTrue == '200') {
_timeElapsed = 0;
var _timer = Timer.periodic(Duration(milliseconds: 200), (timer) {
liftUpButton.postReq();
print("down singal 5per 1 second (ms)");
});
} else {
return false;
}
}
child: GFButton(
onPressed: () {
repeatUpActivate('900');
},
can this help you? to better understand how to cancel a timer
late Timer _timer;
int i = 0;
#override
void initState() {
// TODO: implement initState
super.initState();
launchTimer();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Test")),
body: Center(
child: ElevatedButton(
child: Text('stop timer'),
onPressed: () async {
stopTimer(stopTimer: true);
},
),
),
);
}
void launchTimer() {
_timer = Timer.periodic(Duration(milliseconds: 200), (timer) {
i++;
print(i);
});
}
void stopTimer({required bool stopTimer}) {
if (stopTimer) {
_timer.cancel();
}
}

Unhandled Exception: setState() called after dispose() - due to modal dissmissed

I have a modalBottomSheet. On it, I am displaying several widgets, especially an audioPlayer.
I have find out that when I press the play button, the audio file is playing, so far so good, but if I tap outside the modalBottomSheet, the modal is dismissed. I am OK to get the modal dismissed. But my problem is that when it is dismissed, the player which is running, is generating an exception.
Unhandled Exception: setState() called after dispose()
I do not want to make the Modal not dissmisible.
Please, can you advise? Many thanks.
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/audioplayers_api.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/play_pause_button.dart';
class AudioPlayerWidget extends StatefulWidget {
final String url;
final bool isAsset;
final Duration currentTime;
final Duration totalTime;
final ValueChanged<Duration> onSeekBarMoved;
const AudioPlayerWidget({
Key key,
this.url,
this.isAsset = false,
this.currentTime,
this.totalTime,
this.onSeekBarMoved,
}) : super(key: key);
#override
_AudioPlayerWidgetState createState() => _AudioPlayerWidgetState();
}
class _AudioPlayerWidgetState extends State<AudioPlayerWidget> {
AudioPlayer _audioPlayer;
AudioCache _audioCache;
//variables for slider
Duration _duration = new Duration();
Duration _position = new Duration();
PlayerState _playerState = PlayerState.STOPPED;
bool get _isPlaying => _playerState == PlayerState.PLAYING;
bool get _isLocal => !widget.url.contains('https');
#override
void initState() {
_audioPlayer = AudioPlayer(mode: PlayerMode.MEDIA_PLAYER);
_audioCache = AudioCache(fixedPlayer: _audioPlayer);
_audioPlayer.onDurationChanged.listen((d) {setState(() {
_duration = d;
});});
_audioPlayer.onAudioPositionChanged.listen((p) {setState((){
_position = p;
});});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
_position = Duration(seconds: 0);
_playerState = PlayerState.STOPPED;
});
});
_audioPlayer.onPlayerError.listen((msg) {
print('audioPlayer error : $msg');
setState(() {
_playerState = PlayerState.STOPPED;
});
});
super.initState();
}
#override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(_position.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
Padding(
padding: const EdgeInsets.only(right:18.0),
child: Text(_duration.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
],),
_buildSliderBar(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buttonBackWard10Seconds(),
PlayPauseButton(
isPlaying: _isPlaying,
onPlay: () => _playPause()
),
buttonForward10Seconds(),
//Do not delete iconButton below => for reference
/* IconButton(
onPressed: () => _stop(),
icon: Icon(
Icons.stop,
size: 40,
color: Colors.red,
),
),*/
],
),
],
);
}
//########################################################
_playPause() async {
if (_playerState == PlayerState.PLAYING) {
final playerResult = await _audioPlayer.pause();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PAUSED;
});
}
} else if (_playerState == PlayerState.PAUSED) {
final playerResult = await _audioPlayer.resume();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
} else {
if (widget.isAsset) {
_audioPlayer = await _audioCache.play(widget.url);
setState(() {
_playerState = PlayerState.PLAYING;
});
} else {
final playerResult = await _audioPlayer.play(widget.url, isLocal: _isLocal);
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
}
}
}
void changeToSecond(int second){
Duration newDuration = Duration(seconds:second);
_audioPlayer.seek(newDuration);
}
_stop() async {
final playerResult = await _audioPlayer.stop();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.STOPPED;
});
}
}
//###############################################################
Slider _buildSliderBar(BuildContext context) {
return Slider(
value: _position.inSeconds.toDouble(),
min: 0.0,
max: _duration.inSeconds.toDouble(), //_sliderValue,
activeColor: Colors.red,
inactiveColor: Colors.grey,
onChanged: (double value) {
setState(() {
changeToSecond(value.toInt());
value=value;
});
},
);
}
Widget buttonBackWard10Seconds(){
return IconButton( icon: Icon(CupertinoIcons.gobackward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position - Duration(seconds:10);
if (_position < Duration(seconds:0)) {
_audioPlayer.seek(Duration(seconds: 0));
}
else {
_audioPlayer.seek(_position);
}});
}
Widget buttonForward10Seconds(){
return IconButton( icon:Icon( CupertinoIcons.goforward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position + Duration(seconds:10);
if (_duration >_position) {
_audioPlayer.seek(_position);
}
else if (_duration <_position) {
_audioPlayer.seek(_duration);
}
}
);
}
}
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/audio_player_widget.dart';
import 'package:gtd_official_sharped_focused/Services/extract_file_Name_url/extract_file_name_url.dart';
Widget modalBottomPlayAudio (context,String urlToPlay){
showModalBottomSheet(
context: context,
//background color for modal bottom screen
backgroundColor: Colors.white,
//elevates modal bottom screen
elevation: 10,
// gives rounded corner to modal bottom screen
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
builder: (BuildContext context) {
// UDE : SizedBox instead of Container for whitespaces
return SizedBox(
height: 350,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/*Padding(
padding: const EdgeInsets.all(28.0),
),*/
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(getFileNameFromURL(urlToPlay),
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),),
),
],
),
SizedBox(height: 60,),
AudioPlayerWidget(url:urlToPlay),
],
),
),
);
},
);
}
you could change
setState(()=>{
...
})
to
if(mounted)(
setState(()=>{
...
})
)
Which ensures setState is called only when the widget is mounted on the screen.

Flutter - Life Cycle

Thanks for reading my questions
I wonder again why the error shown below is printed when I navigate to timer page.
I want to know how can I fix it.
The following LateError was thrown while finalizing the widget tree:
LateInitializationError: Field 'timer' has not been initialized.
This is my timer code!
class Pomodoro extends StatefulWidget {
#override
_PomodoroState createState() => _PomodoroState();
}
class _PomodoroState extends State<Pomodoro> {
double coinCount = 0;
Stopwatch watch = Stopwatch();
late Timer timer;
bool startStop = true;
String elapsedTime = '';
#override
void dispose() {
timer.cancel();
super.dispose();
}
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
});
if (coinCount == 360000) {
context.read<Counts>().add(1);
coinCount = 0;
} else {
coinCount = coinCount + 10;
}
context.read<Times>().timeAdd(100);
}
}
restartTimer() {
updateTime(timer).cancel();
setState(() {
startStop = true;
watch.stop();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Container(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(elapsedTime,
style: TextStyle(fontFamily: 'Kitto', fontSize: 25.0)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onPressed: () => startOrStop(),
icon: Image.asset('assets/button.png'),
iconSize: 50,
)
],
)
],
),
),
);
}
startOrStop() {
if (startStop) {
startWatch();
} else {
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
int hours = (minutes / 60).truncate();
String hoursStr = (hours % 60).toString().padLeft(2, '0');
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$hoursStr:$minutesStr:$secondsStr";
}
}
If you know how to fix it, I hope you answered to my question.
I would be grateful for your answer.
And Have a nice day!
I don't think you should use late in that case. Adding late to field means that the field will be initialized when you use it for the first time.
use late when you strongly convinced that first time you use late field it will be initialized. And always remember that using late makes you code less safe and adds possibility of runtime errors.
You don't want a late variable, you want a nullable one. If you need to check if something is initialized, you should be using a nullable variable instead and your code is already set up to check for null.
Just change
late Timer timer;
to
Timer? timer;

stopwatch and timer, problems with flutter

I'm new with dart and flutter and currently I'm studying so please don't judge me for this (maybe) symple question.
I am trying to build a timer but all my code started from a stopwatch so I guess that's the first problem.
In few words, I'm trying to create a timer from 3 minutes that I can stop and start anytime I want (it suppose to be a referee tool) but my starting string is '03:00' and I can see that, so that's fine, I can't find any answer though on how the time can run from 03:00 minutes to 00:00.
Also, as you can see in my code I created a button to reset the time but it always goes back to 00:00 and not to 03:00.
Anyone who can help? I'm definitely missing something.
import 'dart:async';
import 'package:flutter/material.dart';
class NewStopWatch extends StatefulWidget {
#override
_NewStopWatchState createState() => _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
Stopwatch watch = Stopwatch();
Timer timer;
bool startStop = true;
IconData btnPlayStatus = Icons.play_arrow;
String elapsedTime = '03:00';
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(elapsedTime, style: TextStyle(fontSize: 60.0)),
SizedBox(height: 20.0),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
height: 50,
child: FloatingActionButton(
shape: ContinuousRectangleBorder(),
heroTag: "btn1",
backgroundColor: Colors.blueGrey,
onPressed: () => startOrStop(),
child: Icon(btnPlayStatus)),
),
SizedBox(width: 20.0),
Container(
width: 30,
height: 50,
child: FloatingActionButton(
shape: ContinuousRectangleBorder(),
heroTag: "btn2",
backgroundColor: Colors.blueGrey,
onPressed: () => resetWatch(), //resetWatch,
child: Icon(Icons.subdirectory_arrow_left)),
),
],
)
],
),
);
}
resetWatch() {
setState(() {
watch.reset();
setTime();
});
}
startOrStop() {
if(startStop) {
setState(() {
btnPlayStatus = Icons.pause;
});
startWatch();
} else {
setState(() {
btnPlayStatus = Icons.play_arrow;
});
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$minutesStr:$secondsStr";
}
}
First of all you need to think if you always want to start from 3 minutes; if so create a static field as follows:
static duration = new Duration(minutes:3);
Edit: I've refactored your code and made it working.
updateTimer(Timer t) {
if (watch.isRunning) {
setState(() {
Duration newDuration = _NewStopWatchState.duration -
new Duration(milliseconds: watch.elapsedMilliseconds);
elapsedTime = durationToMinutesAndSeconds(newDuration);
});
}
}
This is the updateTimer function.
Next, you didn't update your stopWatch() function to take care of the new changes so I changed it for you.
stopWatch() {
setState(() {
startStop = true;
watch.stop();
Duration newDuration = _NewStopWatchState.duration -
new Duration(milliseconds: watch.elapsedMilliseconds);
elapsedTime = durationToMinutesAndSeconds(newDuration);
});
}
I've also updated the resetWatch() function
resetWatch() {
setState(() {
watch.reset();
elapsedTime = durationToMinutesAndSeconds(_NewStopWatchState.duration);
});
}
I've also created an utility function to convert a duration to minutes and seconds.
String durationToMinutesAndSeconds(Duration d) {
return "${d.inMinutes.toString().padLeft(2, '0')}" +
":${d.inSeconds.remainder(60).toString().padLeft(2, '0')}";
}
I've tried it on my machine and the code is working, hope this time is working even on your side.
That's the modified code:
import 'dart:async';
import 'package:flutter/material.dart';
class NewStopWatch extends StatefulWidget {
#override
_NewStopWatchState createState() => _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
Stopwatch watch = Stopwatch();
Timer timer;
bool startStop = true;
static Duration duration = Duration(minutes:3);
IconData btnPlayStatus = Icons.play_arrow;
String elapsedTime = '';
updateTimer() {
if (watch.isRunning) {
setState(() {
elapsedTime = transformMilliSeconds(_NewStopWatchState.duration.inMilliseconds - watch.elapsedMilliseconds);
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(elapsedTime),
SizedBox(height: 20.0),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
height: 50,
child: FloatingActionButton(
shape: ContinuousRectangleBorder(),
heroTag: "btn1",
backgroundColor: Colors.blueGrey,
onPressed: () => startOrStop(),
child: Icon(btnPlayStatus)),
),
SizedBox(width: 20.0),
Container(
width: 30,
height: 50,
child: FloatingActionButton(
shape: ContinuousRectangleBorder(),
heroTag: "btn2",
backgroundColor: Colors.blueGrey,
onPressed: () => resetWatch(), //resetWatch,
child: Icon(Icons.subdirectory_arrow_left)),
),
],
),
],
),
);
}
resetWatch() {
setState(() {
watch.reset();
setTime();
elapsedTime="${_NewStopWatchState.duration
.inMinutes}:${_NewStopWatchState.duration.inSeconds.remainder(60)}";
});
}
startOrStop() {
if(startStop) {
setState(() {
btnPlayStatus = Icons.pause;
});
startWatch();
} else {
setState(() {
btnPlayStatus = Icons.play_arrow;
});
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTimer());
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$minutesStr:$secondsStr";
}
}
If you want a stop watch also with timer you can use my easy github project.
I hope this will will help some one. Thank you.
Here you can get my github repo

Flutter: Continuously running stopwatch when switching screens

I have a stopwatch widget which is called from the Detailed Activity page on one of my screens that starts when the page loads. How am I able to keep it continuously running in the background so that when I navigate from Detailed Activity to the Home page, I can display that same stopwatch's time?
At the moment, the Home page displays the last saved time (into the variable). Instead I would like this to continue incrementing each second and vice versa switching between the two screens. I've tried adding the startWatch() and initState() method in my Home page, but don't know how to pass the stopwatch value while navigating to the Detailed Activity page
To clarify this more, my thinking was on the Detailed Activity page it is at e.g. 00:15:00 -> pass it into Home page and call initState() to automatically start the timer again. Would this work?
Timer.dart
class NewStopWatch extends StatefulWidget {
#override
_NewStopWatchState createState() => new _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
static _NewStopWatchState stopwatch;
Stopwatch watch = new Stopwatch();
Timer timer;
bool startStop = true;
static String elapsedTime = '';
String duration;
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
User.getCurrentUser().getCurrentActivity().setElapsedTime(elapsedTime);
});
}
}
#override
Widget build(BuildContext context) {
return new Container(
padding: EdgeInsets.all(20.0),
child: new Column(
children: <Widget>[
new Text(elapsedTime, style: new TextStyle(fontSize: 25.0)),
SizedBox(height: 20.0),
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
heroTag: "btn1",
backgroundColor: Colors.red,
onPressed: () => startOrStop(),
child: Icon(Icons.pause)),
SizedBox(width: 20.0),
FloatingActionButton(
heroTag: "btn2",
backgroundColor: Colors.green,
onPressed: () => completeActivity(),
child: Icon(Icons.check)),
],
)
],
));
}
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => startWatch());
}
startOrStop() {
if(startStop) {
startWatch();
} else {
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
resetWatch() {
watch.reset();
setTime();
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
completeActivity() { //do I call activity.stopActivity()?
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Complete Activity?',
style: new TextStyle(color: Colors.black, fontSize: 20.0)),
actions: <Widget>[
new FlatButton(
onPressed: () {
duration = elapsedTime;
print("Current activitiy: ${User.getCurrentUser().getCurrentActivity()}");
// User.getCurrentUser().completeActivity();
User.getCurrentUser().addPastActivity(User.getCurrentUser().getCurrentActivity());
User.getCurrentUser().getCurrentActivity().setStatus(ActivityStatus.completed);
User.getCurrentUser().setCurrentActivity(null);
Navigator.push(context, MaterialPageRoute(builder: (context) => FrontPage()));
// Navigator.popUntil(context, ModalRoute.withName("/"),);
},
child:
new Text('Yes', style: new TextStyle(fontSize: 18.0)),
),
new FlatButton(
onPressed: () => Navigator.pop(context), // this line dismisses the dialog
child: new Text('No', style: new TextStyle(fontSize: 18.0)),
)
],
),
) ??
false;
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
int hours = (minutes / 60).truncate();
String hoursStr = (hours % 60).toString().padLeft(2, '0');
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$hoursStr:$minutesStr:$secondsStr";
}
static String getElapsedTime() {
return elapsedTime;
}
}
It is not 100% clear for me if this solution will work since you posted a lot of code but it is missing the part where you actually display the NewStopWatch but I hope this solution helps:
Pass the Stopwatch and the timer as arguments in the init method of your NewStopWath class and have them passed from your main page - the page where you want them displayed as well... i suppose it is the FrontPage.
Like so:
class FrontPage extends StatelessWidget {
Stopwatch watch = Stopwatch();
Timer timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
//... code
//.. somewhere a NewStopWatch is created
return NewStopWatch(watch, timer);
}
//... code
class NewStopWatch extends StatefulWidget {
Stopwatch watch;
Timer timer;
NewStopWatch(this.watch, this.timer);
#override
_NewStopWatchState createState() => new _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
static _NewStopWatchState stopwatch;
bool startStop = true;
static String elapsedTime = '';
String duration;
Stopwatch get watch => widget.watch;
Timer get timer => widget.timer;
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => startWatch());
}
Be sure to check if you should remove timer = Timer.periodic(Duration(milliseconds: 100), updateTime); from startWatch()
maybe you don't need to have it passed as an argument