cena dos quizzes resolvidos
This commit is contained in:
@@ -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
|
||||
|
||||
// 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(
|
||||
'classIds',
|
||||
arrayContainsAny: classIdList.sublist(
|
||||
i,
|
||||
(i + 10).clamp(0, classIdList.length),
|
||||
),
|
||||
)
|
||||
.orderBy('createdAt', descending: true)
|
||||
.get(),
|
||||
);
|
||||
.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'
|
||||
|
||||
Reference in New Issue
Block a user