cena dos quizzes resolvidos

This commit is contained in:
2026-05-17 15:04:19 +01:00
parent 5649f7d96a
commit 6ba5c837ce

View File

@@ -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<QuizListPage>
}
Future<void> _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<String>()
.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<String>()
.toSet()
.toList();
Logger.info('TeacherIds from classes: $teacherIds');
// Simplificar: tentar query básica primeiro
final classIdList = classIds.toList();
final batches = <Future<QuerySnapshot>>[];
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<String, dynamic>})
.toList();
// Filtrar manualmente para testar
final filteredQuizzes = allQuizzes.where((quiz) {
final quizTeacherId = quiz['teacherId'] as String?;
final quizClassIds = (quiz['classIds'] as List?)?.cast<String>() ?? [];
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 = <String>{};
final quizzes = results
@@ -99,11 +190,19 @@ class _QuizListPageState extends State<QuizListPage>
.where((d) => seen.add(d.id))
.map((d) => {'id': d.id, ...d.data() as Map<String, dynamic>})
.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<QuizListPage>
}
// 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'