From 6ba5c837ce1fe5ec05efa7cce3eea92638721b33 Mon Sep 17 00:00:00 2001 From: 240403 <240403@epvc.pt> Date: Sun, 17 May 2026 15:04:19 +0100 Subject: [PATCH] cena dos quizzes resolvidos --- .../presentation/pages/quiz_list_page.dart | 136 +++++++++++++++--- 1 file changed, 118 insertions(+), 18 deletions(-) diff --git a/lib/features/quiz/presentation/pages/quiz_list_page.dart b/lib/features/quiz/presentation/pages/quiz_list_page.dart index ee58b9a..eb051c9 100644 --- a/lib/features/quiz/presentation/pages/quiz_list_page.dart +++ b/lib/features/quiz/presentation/pages/quiz_list_page.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; @@ -53,45 +54,135 @@ class _QuizListPageState extends State } Future _loadTeacherQuizzes() async { + Logger.info('=== _loadTeacherQuizzes STARTED ==='); try { final uid = FirebaseAuth.instance.currentUser?.uid; if (uid == null) { + Logger.info('User UID is null, returning'); if (mounted) setState(() => _loadingTeacherQuizzes = false); return; } + Logger.info('Loading teacher quizzes for user: $uid'); - // Obter teacherIds dos professores do aluno + // Obter enrollments do aluno final enrollSnap = await FirebaseFirestore.instance .collection('enrollments') .where('studentId', isEqualTo: uid) .get(); + Logger.info('Enrollments found for student $uid: ${enrollSnap.docs.length}'); + final classIds = enrollSnap.docs .map((d) => d.data()['classId'] as String?) .whereType() .toSet(); + Logger.info('ClassIds from enrollments: $classIds'); + if (classIds.isEmpty) { + Logger.info('No classIds found for student, returning empty'); if (mounted) setState(() => _loadingTeacherQuizzes = false); return; } - // Quizzes publicados para as turmas do aluno (array-contains-any, máx 10 por query) + // Obter também os teacherIds (fallback para quizzes sem classIds) + final classSnaps = await Future.wait( + classIds.map((id) => FirebaseFirestore.instance.collection('classes').doc(id).get()), + ); + final teacherIds = classSnaps + .where((d) => d.exists) + .map((d) => d.data()?['teacherId'] as String?) + .whereType() + .toSet() + .toList(); + Logger.info('TeacherIds from classes: $teacherIds'); + + // Simplificar: tentar query básica primeiro final classIdList = classIds.toList(); final batches = >[]; - for (int i = 0; i < classIdList.length; i += 10) { - batches.add( - FirebaseFirestore.instance - .collection('teacherQuizzes') - .where( - 'classIds', - arrayContainsAny: classIdList.sublist( - i, - (i + 10).clamp(0, classIdList.length), - ), - ) - .orderBy('createdAt', descending: true) - .get(), - ); + + // Query 1: por teacherId (mais simples e compatível) + if (teacherIds.isNotEmpty) { + Logger.info('Executing simple teacherIds query with: $teacherIds'); + // Limitar a 10 teacherIds por query (limite do Firestore) + final batch = teacherIds.take(10).toList(); + final query = FirebaseFirestore.instance + .collection('teacherQuizzes') + .where('teacherId', whereIn: batch) + .orderBy('createdAt', descending: true); + batches.add(query.get()); + Logger.info('Added teacherIds batch query: $batch'); } + + // Query 2: por classIds (se a primeira não retornar resultados) + if (classIdList.isNotEmpty) { + Logger.info('Executing classIds query with: $classIdList'); + final batch = classIdList.take(10).toList(); + final query = FirebaseFirestore.instance + .collection('teacherQuizzes') + .where('classIds', arrayContainsAny: batch) + .orderBy('createdAt', descending: true); + batches.add(query.get()); + Logger.info('Added classIds batch query: $batch'); + } + + // Debug: query super simplificada para teste + try { + final testSnap = await FirebaseFirestore.instance + .collection('teacherQuizzes') + .limit(1) + .get(); + Logger.info('=== SUPER SIMPLE TEST QUERY ==='); + Logger.info('Test query result: ${testSnap.docs.length} documents'); + if (testSnap.docs.isNotEmpty) { + final data = testSnap.docs.first.data(); + Logger.info('First quiz data: $data'); + } + Logger.info('=== END TEST QUERY ==='); + } catch (e) { + Logger.error('Super simple test query failed: $e'); + } + + // Teste: retornar todos os quizzes sem filtros (temporário para debug) + try { + final allSnap = await FirebaseFirestore.instance + .collection('teacherQuizzes') + .orderBy('createdAt', descending: true) + .limit(10) + .get(); + Logger.info('=== ALL QUIZZES NO FILTER ==='); + Logger.info('All quizzes count: ${allSnap.docs.length}'); + final allQuizzes = allSnap.docs + .map((d) => {'id': d.id, ...d.data() as Map}) + .toList(); + + // Filtrar manualmente para testar + final filteredQuizzes = allQuizzes.where((quiz) { + final quizTeacherId = quiz['teacherId'] as String?; + final quizClassIds = (quiz['classIds'] as List?)?.cast() ?? []; + return teacherIds.contains(quizTeacherId) || + quizClassIds.any((cid) => classIds.contains(cid)); + }).toList(); + + Logger.info('Manual filtered quizzes: ${filteredQuizzes.length}'); + Logger.info('=== END ALL QUIZZES NO FILTER ==='); + + // Usar este resultado temporariamente para debug + if (filteredQuizzes.isNotEmpty) { + Logger.info('Using manually filtered quizzes for UI'); + if (mounted) { + setState(() { + _teacherQuizzes = filteredQuizzes; + _loadingTeacherQuizzes = false; + }); + } + return; // Sair cedo para não sobrescrever com a query normal + } + } catch (e) { + Logger.error('All quizzes query failed: $e'); + } + + // Executar queries e processar resultados final results = await Future.wait(batches); + Logger.info('Query batches completed: ${results.length} results'); + // deduplicar por id (pode aparecer em múltiplos batches) final seen = {}; final quizzes = results @@ -99,11 +190,19 @@ class _QuizListPageState extends State .where((d) => seen.add(d.id)) .map((d) => {'id': d.id, ...d.data() as Map}) .toList(); - if (mounted) + + Logger.info('Final quizzes after deduplication: ${quizzes.length}'); + for (final quiz in quizzes.take(3)) { + Logger.info('Quiz sample: ${quiz['materialName']} - classIds: ${quiz['classIds']} - teacherId: ${quiz['teacherId']}'); + } + if (mounted) { + Logger.info('Updating UI state: _teacherQuizzes.length = ${quizzes.length}'); setState(() { _teacherQuizzes = quizzes; _loadingTeacherQuizzes = false; }); + Logger.info('UI state updated'); + } } catch (e) { Logger.error('Error loading teacher quizzes: $e'); if (mounted) setState(() => _loadingTeacherQuizzes = false); @@ -154,10 +253,11 @@ class _QuizListPageState extends State } // Gerar quiz via Ollama em formato JSON estruturado + final numQuestions = 5 + Random().nextInt(16); // 5..20 final prompt = 'Usa APENAS o seguinte contexto para criar um quiz. Não uses conhecimento externo.\n\n' '$context\n\n' - 'Cria um quiz com 5 perguntas de escolha múltipla sobre o conteúdo acima.\n' + 'Cria um quiz com EXACTAMENTE $numQuestions perguntas de escolha múltipla sobre o conteúdo acima. Não repitas perguntas.\n' 'Responde SOMENTE com JSON válido, sem texto adicional, sem markdown, sem blocos de código.\n' 'Formato exacto:\n' '[{"q":"Pergunta aqui","opts":["A) opção","B) opção","C) opção","D) opção"],"ans":0,"exp":"Explicação breve da resposta correcta"},...]\n'