stopwatch_page.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_screenutil/flutter_screenutil.dart';
  4. class StopwatchPage extends StatefulWidget {
  5. @override
  6. State<StopwatchPage> createState() => _StopwatchPageState();
  7. }
  8. class _StopwatchPageState extends State<StopwatchPage> {
  9. bool _isRunning = false;
  10. Stopwatch _stopwatch = Stopwatch();
  11. Timer? _timer;
  12. List<String> _laps = [];
  13. @override
  14. void initState() {
  15. super.initState();
  16. }
  17. @override
  18. void dispose() {
  19. _timer?.cancel();
  20. super.dispose();
  21. }
  22. void _startStop() {
  23. setState(() {
  24. if (_isRunning) {
  25. _isRunning = false;
  26. _timer?.cancel();
  27. _stopwatch.stop();
  28. } else {
  29. _isRunning = true;
  30. _stopwatch.start();
  31. _timer = Timer.periodic(Duration(milliseconds: 10), (timer) {
  32. setState(() {});
  33. });
  34. }
  35. });
  36. }
  37. void _resetStopwatch() {
  38. setState(() {
  39. _stopwatch.reset();
  40. _laps.clear();
  41. });
  42. }
  43. void _addLap() {
  44. if (_isRunning) {
  45. setState(() {
  46. _laps.insert(0, _formatTime(_stopwatch.elapsedMilliseconds));
  47. });
  48. }
  49. }
  50. String _formatTime(int milliseconds) {
  51. int hundreds = (milliseconds / 10).truncate() % 100;
  52. int seconds = (milliseconds / 1000).truncate() % 60;
  53. int minutes = (milliseconds / 60000).truncate() % 60;
  54. int hours = (milliseconds / 3600000).truncate();
  55. String hoursStr = hours > 0 ? '${hours.toString().padLeft(2, '0')}:' : '';
  56. String minutesStr = minutes.toString().padLeft(2, '0');
  57. String secondsStr = seconds.toString().padLeft(2, '0');
  58. String hundredsStr = hundreds.toString().padLeft(2, '0');
  59. return '$hoursStr$minutesStr:$secondsStr.$hundredsStr';
  60. }
  61. @override
  62. Widget build(BuildContext context) {
  63. return Scaffold(
  64. backgroundColor: Colors.white,
  65. body: Column(
  66. children: [
  67. SizedBox(height: 50.h),
  68. // Stopwatch display
  69. Text(
  70. _formatTime(_stopwatch.elapsedMilliseconds),
  71. style: TextStyle(
  72. fontSize: 60.sp,
  73. fontWeight: FontWeight.bold,
  74. fontFamily: 'monospace',
  75. ),
  76. ),
  77. SizedBox(height: 30.h),
  78. // Controls
  79. Row(
  80. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  81. children: [
  82. _buildControlButton(
  83. icon: _isRunning ? Icons.pause : Icons.play_arrow,
  84. label: _isRunning ? 'Stop' : 'Start',
  85. onPressed: _startStop,
  86. color: _isRunning ? Colors.red : Colors.green,
  87. ),
  88. _buildControlButton(
  89. icon: Icons.refresh,
  90. label: 'Reset',
  91. onPressed: _stopwatch.elapsedMilliseconds > 0 ? _resetStopwatch : null,
  92. color: Colors.blue,
  93. ),
  94. _buildControlButton(
  95. icon: Icons.flag,
  96. label: 'Lap',
  97. onPressed: _isRunning ? _addLap : null,
  98. color: Colors.orange,
  99. ),
  100. ],
  101. ),
  102. SizedBox(height: 20.h),
  103. // Laps
  104. Expanded(
  105. child: _laps.isEmpty
  106. ? Center(
  107. child: Text(
  108. 'No laps recorded',
  109. style: TextStyle(
  110. fontSize: 16.sp,
  111. color: Colors.grey,
  112. ),
  113. ),
  114. )
  115. : ListView.builder(
  116. itemCount: _laps.length,
  117. itemBuilder: (context, index) {
  118. return ListTile(
  119. dense: true,
  120. leading: CircleAvatar(
  121. radius: 14.r,
  122. backgroundColor: Colors.blue[100],
  123. child: Text(
  124. '${_laps.length - index}',
  125. style: TextStyle(
  126. fontSize: 12.sp,
  127. color: Colors.black87,
  128. ),
  129. ),
  130. ),
  131. title: Text(
  132. 'Lap ${_laps.length - index}',
  133. style: TextStyle(
  134. fontSize: 16.sp,
  135. ),
  136. ),
  137. trailing: Text(
  138. _laps[index],
  139. style: TextStyle(
  140. fontSize: 16.sp,
  141. fontFamily: 'monospace',
  142. fontWeight: FontWeight.bold,
  143. ),
  144. ),
  145. );
  146. },
  147. ),
  148. ),
  149. ],
  150. ),
  151. );
  152. }
  153. Widget _buildControlButton({
  154. required IconData icon,
  155. required String label,
  156. required VoidCallback? onPressed,
  157. required Color color,
  158. }) {
  159. return Column(
  160. children: [
  161. FloatingActionButton(
  162. onPressed: onPressed,
  163. backgroundColor: onPressed == null ? Colors.grey[300] : color,
  164. child: Icon(icon, color: Colors.white),
  165. ),
  166. SizedBox(height: 8.h),
  167. Text(
  168. label,
  169. style: TextStyle(
  170. fontSize: 14.sp,
  171. color: onPressed == null ? Colors.grey : Colors.black87,
  172. ),
  173. ),
  174. ],
  175. );
  176. }
  177. }