import 'dart:async'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/task_item.dart'; class FocusTimerPage extends StatefulWidget { final TaskItem task; const FocusTimerPage({super.key, required this.task}); @override State createState() => _FocusTimerPageState(); } class _FocusTimerPageState extends State with TickerProviderStateMixin { late AnimationController _controller; int _secondsRemaining = 25 * 60; bool _isPlaying = false; Timer? _timer; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 2), ); } @override void dispose() { _timer?.cancel(); _controller.dispose(); super.dispose(); } void _toggleTimer() { setState(() => _isPlaying = !_isPlaying); if (_isPlaying) { _timer = Timer.periodic(const Duration(seconds: 1), (timer) { setState(() { if (_secondsRemaining > 0) { _secondsRemaining--; } else { _isPlaying = false; _timer?.cancel(); HapticFeedback.heavyImpact(); } }); }); _controller.repeat(); } else { _timer?.cancel(); _controller.stop(); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.transparent, leading: IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context), ), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Text( widget.task.title, style: const TextStyle(fontSize: 26, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ), const SizedBox(height: 10), const Text( "Stay focused.", style: TextStyle(color: Colors.grey, fontSize: 16), ), const SizedBox(height: 60), Stack( alignment: Alignment.center, children: [ SizedBox( width: 280, height: 280, child: CircularProgressIndicator( value: _secondsRemaining / (25 * 60), strokeWidth: 12, strokeCap: StrokeCap.round, backgroundColor: Colors.grey.shade100, valueColor: const AlwaysStoppedAnimation( Color(0xFFFF7F50), ), ), ), if (_isPlaying) ScaleTransition( scale: Tween(begin: 0.95, end: 1.05).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ), child: Container( width: 200, height: 200, decoration: BoxDecoration( color: const Color(0xFFFF7F50).withOpacity(0.05), shape: BoxShape.circle, ), ), ), Column( children: [ Text( '${(_secondsRemaining / 60).floor().toString().padLeft(2, '0')}:${(_secondsRemaining % 60).toString().padLeft(2, '0')}', style: const TextStyle( fontSize: 60, fontWeight: FontWeight.w200, fontFeatures: [FontFeature.tabularFigures()], ), ), const SizedBox(height: 24), GestureDetector( onTap: _toggleTimer, child: Container( padding: const EdgeInsets.all(20), decoration: const BoxDecoration( color: Colors.black, shape: BoxShape.circle, ), child: Icon( _isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.white, size: 36, ), ), ) ], ) ], ), const SizedBox(height: 80), ], ), ); } }