import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class StopwatchPage extends StatefulWidget { @override State createState() => _StopwatchPageState(); } class _StopwatchPageState extends State { bool _isRunning = false; Stopwatch _stopwatch = Stopwatch(); Timer? _timer; List _laps = []; @override void initState() { super.initState(); } @override void dispose() { _timer?.cancel(); super.dispose(); } void _startStop() { setState(() { if (_isRunning) { _isRunning = false; _timer?.cancel(); _stopwatch.stop(); } else { _isRunning = true; _stopwatch.start(); _timer = Timer.periodic(Duration(milliseconds: 10), (timer) { setState(() {}); }); } }); } void _resetStopwatch() { setState(() { _stopwatch.reset(); _laps.clear(); }); } void _addLap() { if (_isRunning) { setState(() { _laps.insert(0, _formatTime(_stopwatch.elapsedMilliseconds)); }); } } String _formatTime(int milliseconds) { int hundreds = (milliseconds / 10).truncate() % 100; int seconds = (milliseconds / 1000).truncate() % 60; int minutes = (milliseconds / 60000).truncate() % 60; int hours = (milliseconds / 3600000).truncate(); String hoursStr = hours > 0 ? '${hours.toString().padLeft(2, '0')}:' : ''; String minutesStr = minutes.toString().padLeft(2, '0'); String secondsStr = seconds.toString().padLeft(2, '0'); String hundredsStr = hundreds.toString().padLeft(2, '0'); return '$hoursStr$minutesStr:$secondsStr.$hundredsStr'; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Column( children: [ SizedBox(height: 50.h), // Stopwatch display Text( _formatTime(_stopwatch.elapsedMilliseconds), style: TextStyle( fontSize: 60.sp, fontWeight: FontWeight.bold, fontFamily: 'monospace', ), ), SizedBox(height: 30.h), // Controls Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildControlButton( icon: _isRunning ? Icons.pause : Icons.play_arrow, label: _isRunning ? 'Stop' : 'Start', onPressed: _startStop, color: _isRunning ? Colors.red : Colors.green, ), _buildControlButton( icon: Icons.refresh, label: 'Reset', onPressed: _stopwatch.elapsedMilliseconds > 0 ? _resetStopwatch : null, color: Colors.blue, ), _buildControlButton( icon: Icons.flag, label: 'Lap', onPressed: _isRunning ? _addLap : null, color: Colors.orange, ), ], ), SizedBox(height: 20.h), // Laps Expanded( child: _laps.isEmpty ? Center( child: Text( 'No laps recorded', style: TextStyle( fontSize: 16.sp, color: Colors.grey, ), ), ) : ListView.builder( itemCount: _laps.length, itemBuilder: (context, index) { return ListTile( dense: true, leading: CircleAvatar( radius: 14.r, backgroundColor: Colors.blue[100], child: Text( '${_laps.length - index}', style: TextStyle( fontSize: 12.sp, color: Colors.black87, ), ), ), title: Text( 'Lap ${_laps.length - index}', style: TextStyle( fontSize: 16.sp, ), ), trailing: Text( _laps[index], style: TextStyle( fontSize: 16.sp, fontFamily: 'monospace', fontWeight: FontWeight.bold, ), ), ); }, ), ), ], ), ); } Widget _buildControlButton({ required IconData icon, required String label, required VoidCallback? onPressed, required Color color, }) { return Column( children: [ FloatingActionButton( onPressed: onPressed, backgroundColor: onPressed == null ? Colors.grey[300] : color, child: Icon(icon, color: Colors.white), ), SizedBox(height: 8.h), Text( label, style: TextStyle( fontSize: 14.sp, color: onPressed == null ? Colors.grey : Colors.black87, ), ), ], ); } }