Last active
May 7, 2020 13:45
-
-
Save mingsai/6d1c4e47623d11634353efcb5dfb4b06 to your computer and use it in GitHub Desktop.
Stopwatch Example ( Dependency Injection, multiple listeners for hundredths, seconds, minutes )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'dart:async'; | |
class ElapsedTime { | |
final int hundreds; | |
final int seconds; | |
final int minutes; | |
ElapsedTime({ | |
this.hundreds, | |
this.seconds, | |
this.minutes, | |
}); | |
} | |
class Dependencies { | |
final List<ValueChanged<ElapsedTime>> timerListeners = <ValueChanged<ElapsedTime>>[]; | |
final TextStyle textStyle = const TextStyle(fontSize: 90.0, fontFamily: "Bebas Neue"); | |
final Stopwatch stopwatch = new Stopwatch(); | |
final int timerMillisecondsRefreshRate = 30; | |
} | |
class TimerPage extends StatefulWidget { | |
TimerPage({Key key}) : super(key: key); | |
TimerPageState createState() => new TimerPageState(); | |
} | |
class TimerPageState extends State<TimerPage> { | |
final Dependencies dependencies = new Dependencies(); | |
void leftButtonPressed() { | |
setState(() { | |
if (dependencies.stopwatch.isRunning) { | |
print("${dependencies.stopwatch.elapsedMilliseconds}"); | |
} else { | |
dependencies.stopwatch.reset(); | |
} | |
}); | |
} | |
void rightButtonPressed() { | |
setState(() { | |
if (dependencies.stopwatch.isRunning) { | |
dependencies.stopwatch.stop(); | |
} else { | |
dependencies.stopwatch.start(); | |
} | |
}); | |
} | |
Widget buildFloatingButton(String text, VoidCallback callback) { | |
TextStyle roundTextStyle = const TextStyle(fontSize: 16.0, color: Colors.white); | |
return new FloatingActionButton( | |
child: new Text(text, style: roundTextStyle), | |
onPressed: callback); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return new Column( | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: <Widget>[ | |
new Expanded( | |
child: new TimerText(dependencies: dependencies), | |
), | |
new Expanded( | |
flex: 0, | |
child: new Padding( | |
padding: const EdgeInsets.symmetric(vertical: 10.0), | |
child: new Row( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: <Widget>[ | |
buildFloatingButton(dependencies.stopwatch.isRunning ? "lap" : "reset", leftButtonPressed), | |
buildFloatingButton(dependencies.stopwatch.isRunning ? "stop" : "start", rightButtonPressed), | |
], | |
), | |
), | |
), | |
], | |
); | |
} | |
} | |
class TimerText extends StatefulWidget { | |
TimerText({this.dependencies}); | |
final Dependencies dependencies; | |
TimerTextState createState() => new TimerTextState(dependencies: dependencies); | |
} | |
class TimerTextState extends State<TimerText> { | |
TimerTextState({this.dependencies}); | |
final Dependencies dependencies; | |
Timer timer; | |
int milliseconds; | |
@override | |
void initState() { | |
timer = new Timer.periodic(new Duration(milliseconds: dependencies.timerMillisecondsRefreshRate), callback); | |
super.initState(); | |
} | |
@override | |
void dispose() { | |
timer?.cancel(); | |
timer = null; | |
super.dispose(); | |
} | |
void callback(Timer timer) { | |
if (milliseconds != dependencies.stopwatch.elapsedMilliseconds) { | |
milliseconds = dependencies.stopwatch.elapsedMilliseconds; | |
final int hundreds = (milliseconds / 10).truncate(); | |
final int seconds = (hundreds / 100).truncate(); | |
final int minutes = (seconds / 60).truncate(); | |
final ElapsedTime elapsedTime = new ElapsedTime( | |
hundreds: hundreds, | |
seconds: seconds, | |
minutes: minutes, | |
); | |
for (final listener in dependencies.timerListeners) { | |
listener(elapsedTime); | |
} | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return new Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
new RepaintBoundary( | |
child: new SizedBox( | |
height: 72.0, | |
child: new MinutesAndSeconds(dependencies: dependencies), | |
), | |
), | |
new RepaintBoundary( | |
child: new SizedBox( | |
height: 72.0, | |
child: new Hundreds(dependencies: dependencies), | |
), | |
), | |
], | |
); | |
} | |
} | |
class MinutesAndSeconds extends StatefulWidget { | |
MinutesAndSeconds({this.dependencies}); | |
final Dependencies dependencies; | |
MinutesAndSecondsState createState() => new MinutesAndSecondsState(dependencies: dependencies); | |
} | |
class MinutesAndSecondsState extends State<MinutesAndSeconds> { | |
MinutesAndSecondsState({this.dependencies}); | |
final Dependencies dependencies; | |
int minutes = 0; | |
int seconds = 0; | |
@override | |
void initState() { | |
dependencies.timerListeners.add(onTick); | |
super.initState(); | |
} | |
void onTick(ElapsedTime elapsed) { | |
if (elapsed.minutes != minutes || elapsed.seconds != seconds) { | |
setState(() { | |
minutes = elapsed.minutes; | |
seconds = elapsed.seconds; | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
String minutesStr = (minutes % 60).toString().padLeft(2, '0'); | |
String secondsStr = (seconds % 60).toString().padLeft(2, '0'); | |
return new Text('$minutesStr:$secondsStr.', style: dependencies.textStyle); | |
} | |
} | |
class Hundreds extends StatefulWidget { | |
Hundreds({this.dependencies}); | |
final Dependencies dependencies; | |
HundredsState createState() => new HundredsState(dependencies: dependencies); | |
} | |
class HundredsState extends State<Hundreds> { | |
HundredsState({this.dependencies}); | |
final Dependencies dependencies; | |
int hundreds = 0; | |
@override | |
void initState() { | |
dependencies.timerListeners.add(onTick); | |
super.initState(); | |
} | |
void onTick(ElapsedTime elapsed) { | |
if (elapsed.hundreds != hundreds) { | |
setState(() { | |
hundreds = elapsed.hundreds; | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
String hundredsStr = (hundreds % 100).toString().padLeft(2, '0'); | |
return new Text(hundredsStr, style: dependencies.textStyle); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment