import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import '../../../../core/theme/app_theme_extension.dart'; import '../../../../core/services/gamification_service.dart'; import '../../../../core/models/user_stats.dart'; import '../../../../core/services/auth_service.dart'; /// Progress tracking hero section for student dashboard class ProgressHeroWidget extends StatefulWidget { final String userName; const ProgressHeroWidget({super.key, required this.userName}); @override State createState() => _ProgressHeroWidgetState(); } class _ProgressHeroWidgetState extends State { @override Widget build(BuildContext context) { return FutureBuilder( future: _loadUserStats(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return _buildLoadingState(); } if (snapshot.hasError) { return _buildErrorState(); } final userStats = snapshot.data; return _buildContent(userStats); }, ); } Future _loadUserStats() async { try { final user = AuthService.currentUser; if (user != null) { return await GamificationService.getUserStats(user.uid); } return null; } catch (e) { print('Error loading user stats: $e'); return null; } } double _calculateOverallProgress(UserStats? userStats) { if (userStats == null || userStats.masteredConcepts.isEmpty) { return 0.0; } final totalMastery = userStats.masteredConcepts .map((c) => c.masteryLevel) .reduce((a, b) => a + b); return totalMastery / (userStats.masteredConcepts.length * 100); } Widget _buildLoadingState() { return const Center(child: CircularProgressIndicator()); } Widget _buildErrorState() { return const Center(child: Text('Erro ao carregar dados')); } Widget _buildContent(UserStats? userStats) { final streakDays = userStats?.currentStreak ?? 0; final overallProgress = _calculateOverallProgress(userStats); final masteredConcepts = userStats?.masteredConcepts.map((c) => c.conceptName).toList() ?? []; final studyTimeMinutes = userStats?.totalStudyTime ?? 0; return Container( margin: const EdgeInsets.only(bottom: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Seu Progresso', style: TextStyle( color: Theme.of(context).colorScheme.onSurface, fontSize: 24, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( 'Continue assim, ${widget.userName}!', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 16, ), ), ], ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.local_fire_department, color: Colors.white, size: 16, ), const SizedBox(width: 4), Text( '$streakDays dias', style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), ], ), ), ], ), const SizedBox(height: 20), // Main Progress Card Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.primary.withOpacity(0.8), ], ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Overall Progress Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Progresso Geral', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), Text( '${(overallProgress * 100).toInt()}%', style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 16), // Progress Bar GestureDetector( onTap: () => _showProgressExplanation(context), child: Container( height: 12, decoration: BoxDecoration( color: Colors.white.withOpacity(0.3), borderRadius: BorderRadius.circular(6), ), child: FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: overallProgress, child: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppThemeExtras.of(context).heroProgressStart, AppThemeExtras.of(context).heroProgressEnd, ], ), borderRadius: BorderRadius.circular(6), ), ), ), ), ), const SizedBox(height: 20), // Stats Grid Row( children: [ Expanded( child: GestureDetector( onTap: () => _showStudyTimeDetails(context, userStats), child: _buildStatCard( icon: Icons.access_time, value: '${(studyTimeMinutes / 60).toStringAsFixed(1)}h', label: 'Tempo de Estudo', ), ), ), const SizedBox(width: 12), Expanded( child: _buildStatCard( icon: Icons.emoji_events, value: '${masteredConcepts.length}', label: 'Conceitos Dominados', ), ), ], ), ], ), ), const SizedBox(height: 20), // Mastered Concepts Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(16), border: Border.all( color: Theme.of( context, ).colorScheme.outline.withOpacity(0.2), ), boxShadow: [ BoxShadow( color: Theme.of( context, ).colorScheme.shadow.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.school, color: Theme.of(context).colorScheme.secondary, size: 20, ), const SizedBox(width: 8), Text( 'Conceitos Dominados', style: TextStyle( color: Theme.of(context).colorScheme.onSurface, fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 12), ...masteredConcepts.map( (concept) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, shape: BoxShape.circle, ), ), const SizedBox(width: 12), Expanded( child: Text( concept, style: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, fontSize: 14, ), ), ), Icon( Icons.check_circle, color: Theme.of(context).colorScheme.primary, size: 16, ), ], ), ), ), ], ), ) .animate() .fadeIn( duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ) .then(delay: const Duration(milliseconds: 200)), ], ), ); } Widget _buildStatCard({ required IconData icon, required String value, required String label, }) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withOpacity(0.3), width: 1), ), child: Column( children: [ Icon(icon, color: Colors.white, size: 24), const SizedBox(height: 8), Text( value, style: const TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( label, style: const TextStyle(color: Colors.white, fontSize: 12), textAlign: TextAlign.center, ), ], ), ); } void _showProgressExplanation(BuildContext context) { final cs = Theme.of(context).colorScheme; showDialog( context: context, builder: (ctx) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.info_outline, color: cs.primary), const SizedBox(width: 8), const Text('Progresso Geral'), ], ), content: const Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'O Progresso Geral representa a média dos níveis de domínio dos conceitos que já dominaste.', style: TextStyle(fontSize: 14), ), SizedBox(height: 12), Text( 'Como é calculado:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), ), SizedBox(height: 8), Text( '• Cada conceito tem um nível de 0 a 100\n' '• O progresso é a média de todos os conceitos dominados\n' '• Quanto mais alto, melhor o teu domínio', style: TextStyle(fontSize: 13, color: Colors.grey), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('Entendi'), ), ], ), ); } void _showStudyTimeDetails(BuildContext context, UserStats? userStats) { final cs = Theme.of(context).colorScheme; final totalMinutes = userStats?.totalStudyTime ?? 0; final weeklyMinutes = userStats?.weeklyStudyTime ?? 0; final monthlyMinutes = userStats?.monthlyStudyTime ?? 0; showDialog( context: context, builder: (ctx) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.access_time, color: cs.primary), const SizedBox(width: 8), const Text('Tempo de Estudo'), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTimeRow('Total', totalMinutes, cs), const SizedBox(height: 12), _buildTimeRow('Esta semana', weeklyMinutes, cs), const SizedBox(height: 12), _buildTimeRow('Este mês', monthlyMinutes, cs), const SizedBox(height: 16), const Text( 'O tempo é contado automaticamente quando completas quizzes.', style: TextStyle(fontSize: 12, color: Colors.grey), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('Fechar'), ), ], ), ); } Widget _buildTimeRow(String label, int minutes, ColorScheme cs) { final hours = minutes ~/ 60; final mins = minutes % 60; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: TextStyle(fontSize: 14, color: cs.onSurface)), Text( hours > 0 ? '${hours}h ${mins}min' : '${mins}min', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: cs.primary, ), ), ], ); } }