import 'package:flutter/material.dart'; import 'constants/app_colors.dart'; import 'constants/app_strings.dart'; import 'screens/google_map_screen.dart'; import 'screens/bluetooth_connection_screen.dart'; void main() { // Ponto de entrada do aplicativo. runApp(const MyApp()); } /// Widget raiz do aplicativo que configura o MaterialApp. class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( // Remove a bandeira de "debug" no canto superior direito. debugShowCheckedModeBanner: false, // Define a tela inicial como RunningScreen. home: RunningScreen(), ); } } /// Tela principal que exibe o progresso, estatísticas e menu. class RunningScreen extends StatefulWidget { const RunningScreen({super.key}); @override State createState() => _RunningScreenState(); } class _RunningScreenState extends State with SingleTickerProviderStateMixin { // Variáveis de estado para controlar os dados da corrida. double progress = 0.35; // Progresso inicial simulado para estética. double targetDistance = 8.0; // Distância alvo em KM. double currentDistance = 2.8; // Distância atual percorrida simulada. /// Constrói o indicador de progresso circular central com melhorias estéticas. Widget _buildCircularProgressIndicator() { return SizedBox( width: 210, height: 210, child: Stack( alignment: Alignment.center, children: [ // Efeito de brilho (glow) sutil atrás do progresso. Container( width: 180, height: 180, decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: AppColors.white.withOpacity(0.05), blurRadius: 30, spreadRadius: 10, ), ], ), ), // TweenAnimationBuilder cria uma animação suave quando o valor do progresso muda. TweenAnimationBuilder( tween: Tween(begin: 0.0, end: progress), duration: const Duration(seconds: 1), curve: Curves.easeInOut, builder: (context, value, _) { return CustomPaint( size: const Size(210, 210), painter: CircularProgressPainter( progress: value, strokeWidth: 14, progressColor: AppColors.white, backgroundColor: AppColors.white.withOpacity(0.15), ), ); }, ), // Círculo interno que contém o texto da porcentagem. Container( width: 175, height: 175, decoration: const BoxDecoration( color: AppColors.backgroundGrey, shape: BoxShape.circle, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "${(progress * 100).toInt()}%", style: const TextStyle( fontSize: 42, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: -1, ), ), Text( AppStrings.complete, style: TextStyle( color: Colors.white.withOpacity(0.5), fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 1.5, ), ), ], ), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, // Cor de fundo escura definida nas constantes. body: Stack( children: [ // 1. Indicador de progresso circular posicionado no topo central. Align( alignment: Alignment.topCenter, child: Padding( padding: const EdgeInsets.only(top: 70), child: _buildCircularProgressIndicator(), ), ), // 2. Exibição da distância estilizada como um badge. Positioned( top: 300, left: 0, right: 0, child: Center( child: Container( padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.08), borderRadius: BorderRadius.circular(25), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Text( "${currentDistance.toStringAsFixed(1)} ${AppStrings.kmUnit} | ${targetDistance.toStringAsFixed(1)} ${AppStrings.kmUnit}", style: const TextStyle( color: AppColors.white, fontSize: 15, fontWeight: FontWeight.w800, letterSpacing: 0.5, ), ), ), ), ), // 3. Contêiner de estatísticas e o mapa interativo. Positioned( top: 360, left: 20, right: 20, child: Container( height: 210, decoration: BoxDecoration( color: AppColors.backgroundGrey, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: Row( children: [ // Lado Esquerdo: Estatísticas. Expanded( flex: 4, child: Padding( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildStatItem(Icons.directions_run_rounded, "3219", AppStrings.steps), Divider(color: Colors.white.withOpacity(0.1), height: 1), _buildStatItem(Icons.favorite_rounded, "98", AppStrings.bpm), Divider(color: Colors.white.withOpacity(0.1), height: 1), _buildStatItem(Icons.local_fire_department_rounded, "480", AppStrings.kcal), ], ), ), ), // Lado Direito: Miniatura do Mapa Clicável. Expanded( flex: 6, child: GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const GoogleMapScreen()), ); }, child: Container( margin: const EdgeInsets.all(8), child: ClipRRect( borderRadius: BorderRadius.circular(22), child: Stack( children: [ Container(color: const Color(0xFF2C2C2E)), CustomPaint( size: Size.infinite, painter: MapPainter(), ), // Overlay estético indicando interatividade. Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Colors.black.withOpacity(0.4), ], ), ), ), Positioned( bottom: 12, right: 12, child: Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: AppColors.background.withOpacity(0.8), shape: BoxShape.circle, ), child: const Icon(Icons.fullscreen_rounded, color: Colors.white, size: 20), ), ), const Positioned( top: 12, left: 12, child: Text( AppStrings.mapPreview, style: TextStyle( color: Colors.white, fontSize: 10, fontWeight: FontWeight.w900, letterSpacing: 1, ), ), ), ], ), ), ), ), ), ], ), ), ), // 4. Barra de progresso linear centralizada. Positioned( bottom: 170, left: 50, right: 50, child: ClipRRect( borderRadius: BorderRadius.circular(10), child: LinearProgressIndicator( value: progress, minHeight: 8, backgroundColor: Colors.white.withOpacity(0.1), valueColor: const AlwaysStoppedAnimation(AppColors.white), ), ), ), // 5. Menu de navegação inferior. Positioned( bottom: 50, left: 0, right: 0, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildMenuButton(Icons.settings_outlined, AppStrings.settings), _buildMenuButton(Icons.group_outlined, AppStrings.groups), _buildMenuButton(Icons.history_rounded, AppStrings.history), _buildMenuButton(Icons.notifications_none_rounded, AppStrings.notifications, showBadge: true), _buildMenuButton(Icons.person_outline_rounded, AppStrings.profile, isAvatar: true), ], ), ), // 6. Ação rápida de Bluetooth. Positioned( top: 60, right: 25, child: _buildSmallActionButton(Icons.bluetooth, Colors.red), ), ], ), ); } /// Item de estatística com design refinado. Widget _buildStatItem(IconData icon, String value, String label) { return Row( children: [ Icon(icon, color: AppColors.coral.withOpacity(0.8), size: 22), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( value, style: const TextStyle( color: Colors.white, fontSize: 19, fontWeight: FontWeight.w900, ), ), Text( label, style: TextStyle( color: Colors.white.withOpacity(0.4), fontSize: 9, fontWeight: FontWeight.bold, letterSpacing: 0.5, ), ), ], ), ], ); } /// Botões do menu com melhorias visuais. Widget _buildMenuButton(IconData icon, String message, {bool showBadge = false, bool isAvatar = false}) { return GestureDetector( onTap: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 1), ), ); }, child: Stack( clipBehavior: Clip.none, children: [ isAvatar ? Container( padding: const EdgeInsets.all(3), decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: AppColors.coral, width: 2), ), child: const CircleAvatar( radius: 18, backgroundImage: NetworkImage('https://i.pravatar.cc/150?u=1'), ), ) : Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.backgroundGrey, borderRadius: BorderRadius.circular(18), border: Border.all(color: Colors.white.withOpacity(0.05)), ), child: Icon(icon, color: Colors.white.withOpacity(0.9), size: 24), ), if (showBadge) Positioned( right: -2, top: -2, child: Container( width: 10, height: 10, decoration: BoxDecoration( color: AppColors.coral, shape: BoxShape.circle, border: Border.all(color: AppColors.background, width: 2), ), ), ), ], ), ); } /// Botão de ação rápida (Bluetooth). Widget _buildSmallActionButton(IconData icon, Color badgeColor) { return GestureDetector( onTap: () { // Navegando para a nova tela de conexão Bluetooth Navigator.push( context, MaterialPageRoute(builder: (context) => const BluetoothConnectionScreen()), ); }, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppColors.backgroundGrey, shape: BoxShape.circle, border: Border.all(color: Colors.white.withOpacity(0.05)), ), child: Stack( children: [ Icon(icon, color: Colors.white, size: 20), Positioned( right: 0, top: 0, child: Container( width: 7, height: 7, decoration: BoxDecoration( color: badgeColor, shape: BoxShape.circle, border: Border.all(color: AppColors.backgroundGrey, width: 1.5), ), ), ), ], ), ), ); } } /// Pintor customizado para o mapa miniatura estético. class MapPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paintPath = Paint() ..color = AppColors.coral.withOpacity(0.5) ..strokeWidth = 3 ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round; final path = Path(); path.moveTo(size.width * 0.1, size.height * 0.8); path.quadraticBezierTo(size.width * 0.3, size.height * 0.9, size.width * 0.5, size.height * 0.5); path.quadraticBezierTo(size.width * 0.7, size.height * 0.1, size.width * 0.9, size.height * 0.3); final paintRoad = Paint() ..color = Colors.white.withOpacity(0.1) ..strokeWidth = 10 ..style = PaintingStyle.stroke; final road = Path(); road.moveTo(0, size.height * 0.5); road.lineTo(size.width, size.height * 0.6); canvas.drawPath(road, paintRoad); canvas.drawPath(path, paintPath); final markerPaint = Paint()..color = AppColors.coral; canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), 5, markerPaint); canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), 8, Paint()..color = AppColors.coral.withOpacity(0.3)); } @override bool shouldRepaint(CustomPainter oldDelegate) => false; } /// Pintor customizado para o arco de progresso circular. class CircularProgressPainter extends CustomPainter { final double progress; final double strokeWidth; final Color progressColor; final Color backgroundColor; CircularProgressPainter({ required this.progress, required this.strokeWidth, required this.progressColor, required this.backgroundColor, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = (size.width - strokeWidth) / 2; canvas.drawCircle(center, radius, Paint() ..color = backgroundColor ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke); final progressPaint = Paint() ..color = progressColor ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), -1.5708, // -90 graus em radianos 6.2831 * progress, // 360 graus em radianos * progresso false, progressPaint, ); } @override bool shouldRepaint(covariant CircularProgressPainter oldDelegate) => oldDelegate.progress != progress; }