// lib/screens/quiz_screen.dart // (Manter as importações) import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:kzeduca_app/services/i18n_service.dart'; import 'package:kzeduca_app/services/firebase_service.dart'; import 'package:kzeduca_app/models/app_models.dart'; import 'dart:math'; import 'daily_quiz_screen.dart'; // Importar a nova tela do quiz diário class QuizScreen extends StatefulWidget { const QuizScreen({super.key}); @override State createState() => _QuizScreenState(); } class _QuizScreenState extends State { List _allQuestions = []; List _currentQuizQuestions = []; List _quizResults = []; bool _isLoading = true; String _error = ''; bool _quizStarted = false; int _currentQuestionIndex = 0; int _score = 0; String? _selectedOption; bool _showAnswerFeedback = false; bool _quizFinished = false; FinancialChallenge? _dailyChallengeNotification; @override void initState() { super.initState(); _loadAllQuizData(); _checkDailyChallengeStatus(); } // (Manter _showAlertDialog e _checkDailyChallengeStatus) void _showAlertDialog(String message, {bool isError = false}) { final i18n = Provider.of(context, listen: false); showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(isError ? i18n.t('error_prefix') : 'Info'), content: Text(message), actions: [ TextButton( child: const Text('Ok'), onPressed: () { Navigator.of(ctx).pop(); }, ) ], ), ); } Future _checkDailyChallengeStatus() async { final prefs = await SharedPreferences.getInstance(); final lastCompletionDate = prefs.getString('daily_quiz_completion_date'); final today = DateFormat('yyyy-MM-dd').format(DateTime.now()); // A notificação deve aparecer se nunca foi completada hoje if (lastCompletionDate != today) { final firebaseService = Provider.of(context, listen: false); try { final allChallenges = await firebaseService.getAllChallenges(); if (allChallenges.isNotEmpty) { final random = Random(); setState(() { _dailyChallengeNotification = allChallenges[random.nextInt(allChallenges.length)]; }); } } catch (e) { print("Erro ao carregar desafios para notificação: $e"); } } else { setState(() { _dailyChallengeNotification = null; }); } } Future _loadAllQuizData() async { final firebaseService = Provider.of(context, listen: false); final userId = FirebaseAuth.instance.currentUser?.uid; setState(() { _isLoading = true; _error = ''; }); try { final querySnapshot = await firebaseService.firestore .collection('artifacts') .doc('default-kzeduca-app') .collection('public') .doc('data') .collection('quizQuestions') .get(); _allQuestions = querySnapshot.docs.map((doc) => QuizQuestion.fromFirestore(doc)).toList(); // Carrega resultados do utilizador firebaseService.streamUserQuizResults(userId!).listen((snapshot) { if (mounted) { setState(() { _quizResults = snapshot.docs.map((doc) => UserQuizResult.fromFirestore(doc)).toList(); _quizResults.sort((a, b) => DateTime.parse(b.timestamp).compareTo(DateTime.parse(a.timestamp))); }); } }); } catch (e) { print("Erro geral ao carregar dados do quiz: $e"); if (mounted) { _showAlertDialog("Erro ao carregar dados do quiz.", isError: true); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } void _startRandomQuiz() { if (_allQuestions.length < 5) { _showAlertDialog('Não há perguntas suficientes para começar o quiz.'); return; } _allQuestions.shuffle(); _currentQuizQuestions = _allQuestions.take(5).toList(); setState(() { _quizStarted = true; _quizFinished = false; _currentQuestionIndex = 0; _score = 0; _selectedOption = null; _showAnswerFeedback = false; }); } // Resto da lógica do quiz (handleAnswer, handleNextQuestion, saveQuizResult) Future _handleAnswer(String option) async { if (_showAnswerFeedback) return; setState(() { _selectedOption = option; _showAnswerFeedback = true; if (option == _currentQuizQuestions[_currentQuestionIndex].answer) { _score++; } }); // Lógica para ir para a próxima pergunta await Future.delayed(const Duration(seconds: 2)); if (mounted) { _handleNextQuestion(); } } Future _handleNextQuestion() async { setState(() { _selectedOption = null; _showAnswerFeedback = false; }); if (_currentQuestionIndex < _currentQuizQuestions.length - 1) { setState(() { _currentQuestionIndex++; }); } else { await _saveQuizResult(); setState(() { _quizStarted = false; _quizFinished = true; }); } } Future _saveQuizResult() async { final i18n = Provider.of(context, listen: false); final firebaseService = Provider.of(context, listen: false); final userId = FirebaseAuth.instance.currentUser?.uid; if (userId == null || _currentQuizQuestions.isEmpty) { _showAlertDialog(i18n.t('quiz_save_error'), isError: true); return; } try { await firebaseService.saveQuizResult(userId, { 'score': _score, 'totalQuestions': _currentQuizQuestions.length, 'timestamp': DateTime.now().toIso8601String(), }); _showAlertDialog(i18n.t('quiz_saved')); } catch (e) { print("Erro ao salvar resultado do quiz: $e"); _showAlertDialog(i18n.t('quiz_save_error'), isError: true); } } void _showDailyChallengeNotificationDialog(FinancialChallenge challenge) { final i18n = Provider.of(context, listen: false); showDialog( context: context, builder: (ctx) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), backgroundColor: Colors.purple[900]?.withOpacity(0.8), title: Text( i18n.t('bonus_daily_challenge'), style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.star, color: Colors.amber, size: 40), const SizedBox(height: 10), Text( '${i18n.t('congratulations_quiz_bonus_intro')}!', style: const TextStyle(color: Colors.white, fontSize: 16), ), const SizedBox(height: 20), Text( challenge.nome, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), const SizedBox(height: 5), Text( challenge.meta, style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14), ), ], ), actions: [ TextButton( child: Text( i18n.t('accept_challenge'), style: const TextStyle(color: Colors.amber, fontWeight: FontWeight.bold), ), onPressed: () { Navigator.of(ctx).pop(); }, ), TextButton( child: Text( i18n.t('later'), style: TextStyle(color: Colors.white.withOpacity(0.7)), ), onPressed: () { Navigator.of(ctx).pop(); }, ), ], ), ); } @override Widget build(BuildContext context) { final i18n = Provider.of(context); return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( title: Text(i18n.t('financial_quiz')), backgroundColor: Colors.black.withOpacity(0.5), foregroundColor: Colors.white, elevation: 0, ), body: Stack( children: [ Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/quiz_background.png'), fit: BoxFit.cover, ), ), ), Center( child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Container( padding: const EdgeInsets.all(32.0), decoration: BoxDecoration( color: Colors.black.withOpacity(0.7), borderRadius: BorderRadius.circular(24.0), border: Border.all(color: Colors.white.withOpacity(0.2)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.5), blurRadius: 32, offset: const Offset(0, 8), ), ], ), constraints: const BoxConstraints(maxWidth: 600), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (_dailyChallengeNotification != null) GestureDetector( onTap: () { // Navegar para a tela do quiz diário Navigator.push( context, MaterialPageRoute( builder: (context) => DailyQuizScreen( dailyChallenge: _dailyChallengeNotification!, ), ), ).then((_) => _checkDailyChallengeStatus()); // Atualiza o estado ao voltar }, child: Container( padding: const EdgeInsets.all(16), margin: const EdgeInsets.only(bottom: 24), decoration: BoxDecoration( color: Colors.purple[800]?.withOpacity(0.8), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.amber, width: 2), ), child: Row( children: [ const Icon(Icons.notifications_active, color: Colors.amber, size: 30), const SizedBox(width: 16), Expanded( child: Text( i18n.t('daily_challenge_notification'), style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), const Icon(Icons.arrow_forward_ios, color: Colors.white, size: 16), ], ), ), ), Text( i18n.t('test_knowledge'), style: TextStyle(fontSize: 16, color: Colors.white.withOpacity(0.7)), textAlign: TextAlign.center, ), const SizedBox(height: 24), if (_isLoading) const Center(child: CircularProgressIndicator()) else if (_allQuestions.isEmpty) Text( 'Nenhuma pergunta de quiz disponível. Por favor, adicione perguntas no Firestore.', style: TextStyle(color: Colors.white.withOpacity(0.8)), textAlign: TextAlign.center, ) else if (!_quizStarted && !_quizFinished) Column( children: [ Icon(Icons.lightbulb_outline, size: 80, color: Colors.teal[400]), const SizedBox(height: 16), Text( i18n.t('ready_for_challenge'), style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), textAlign: TextAlign.center, ), const SizedBox(height: 10), Text( 'Teste os seus conhecimentos sobre finanças de forma divertida e interativa!', style: TextStyle(fontSize: 16, color: Colors.white.withOpacity(0.7)), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: _startRandomQuiz, // Inicia o quiz aleatório de 5 perguntas icon: const Icon(Icons.play_arrow), label: Text(i18n.t('start_quiz')), style: ElevatedButton.styleFrom( backgroundColor: Colors.teal[500], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 30), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 8, shadowColor: Colors.teal[300]?.withOpacity(0.5), ), ), const SizedBox(height: 30), Text( i18n.t('quiz_results_history'), style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white), textAlign: TextAlign.center, ), const SizedBox(height: 16), _quizResults.isEmpty ? Text(i18n.t('no_quiz_results'), style: TextStyle(color: Colors.white.withOpacity(0.6)), textAlign: TextAlign.center) : ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _quizResults.length, itemBuilder: (context, index) { final result = _quizResults[index]; return Card( elevation: 2, margin: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), color: Colors.black.withOpacity(0.4), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( i18n.t('your_score', options: { 'score': result.score.toString(), 'total': result.totalQuestions.toString(), }), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), ), Text( 'Em: ${DateFormat('dd/MM/yyyy HH:mm').format(DateTime.parse(result.timestamp).toLocal())}', style: TextStyle(fontSize: 14, color: Colors.white.withOpacity(0.7)), ), if (result.score / result.totalQuestions >= 0.7) Align( alignment: Alignment.bottomRight, child: Text('Parabéns! Ótimo resultado!', style: TextStyle(color: Colors.green[300], fontStyle: FontStyle.italic)), ) ], ), ), ); }, ), ], ) else if (_quizStarted && !_quizFinished) Column( children: [ LinearProgressIndicator( value: (_currentQuestionIndex + 1) / _currentQuizQuestions.length, backgroundColor: Colors.white.withOpacity(0.3), color: Colors.teal[400], minHeight: 10, borderRadius: BorderRadius.circular(5), ), const SizedBox(height: 16), Text( 'Questão ${_currentQuestionIndex + 1} de ${_currentQuizQuestions.length}', style: TextStyle(fontSize: 14, color: Colors.white.withOpacity(0.6)), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( _currentQuizQuestions[_currentQuestionIndex].question, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white), textAlign: TextAlign.center, ), const SizedBox(height: 24), ..._currentQuizQuestions[_currentQuestionIndex].options.map((option) { bool isCorrect = option == _currentQuizQuestions[_currentQuestionIndex].answer; bool isSelected = option == _selectedOption; return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: ElevatedButton( onPressed: _showAnswerFeedback ? null : () => _handleAnswer(option), style: ElevatedButton.styleFrom( backgroundColor: _showAnswerFeedback ? (isCorrect ? Colors.green[500] : Colors.red[500]) : Colors.black.withOpacity(0.4), foregroundColor: Colors.white, side: BorderSide( color: _showAnswerFeedback ? (isCorrect ? Colors.green[400]! : Colors.red[400]!) : Colors.white.withOpacity(0.3), width: 1, ), padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: isSelected ? 4 : 2, ), child: Align( alignment: Alignment.centerLeft, child: Text(option, style: const TextStyle(fontSize: 16)), ), ), ); }), if (_showAnswerFeedback) ...[ const SizedBox(height: 16), Card( elevation: 4, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), color: _selectedOption == _currentQuizQuestions[_currentQuestionIndex].answer ? Colors.green[900]?.withOpacity(0.6) : Colors.red[900]?.withOpacity(0.6), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _selectedOption == _currentQuizQuestions[_currentQuestionIndex].answer ? i18n.t('correct') : i18n.t('incorrect'), style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 8), Text( _currentQuizQuestions[_currentQuestionIndex].explanation, style: TextStyle(fontSize: 16, color: Colors.white.withOpacity(0.9)), ), ], ), ), ), ], const SizedBox(height: 24), ElevatedButton.icon( onPressed: _showAnswerFeedback ? _handleNextQuestion : null, icon: Icon(_currentQuestionIndex < _currentQuizQuestions.length - 1 ? Icons.arrow_forward : Icons.bar_chart), label: Text( _currentQuestionIndex < _currentQuizQuestions.length - 1 ? i18n.t('next_question') : i18n.t('view_results'), ), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue[500], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 8, shadowColor: Colors.blue[300]?.withOpacity(0.5), ), ), ], ) else if (_quizFinished) Column( children: [ Icon(Icons.emoji_events, size: 80, color: Colors.amber[600]), const SizedBox(height: 16), Text( i18n.t('quiz_finished'), style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), textAlign: TextAlign.center, ), const SizedBox(height: 10), Text( i18n.t('your_final_score', options: { 'score': _score.toString(), 'total': _currentQuizQuestions.length.toString(), }), style: TextStyle(fontSize: 20, color: Colors.teal[300], fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () { _startRandomQuiz(); }, icon: const Icon(Icons.refresh), label: Text(i18n.t('retake_quiz')), style: ElevatedButton.styleFrom( backgroundColor: Colors.teal[500], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 30), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 8, shadowColor: Colors.teal[300]?.withOpacity(0.5), ), ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: () { _quizFinished = false; _quizStarted = false; setState(() {}); }, icon: const Icon(Icons.history), label: Text(i18n.t('view_all_results')), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[500], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 30), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 8, ), ), ], ), ], ), ), ), ), ], ), ); } }