Teacher dashboard updates

This commit is contained in:
2026-05-24 20:09:22 +01:00
parent 1a98fff5e8
commit c2fd663170
6 changed files with 301 additions and 307 deletions

View File

@@ -11,6 +11,7 @@ import 'package:path/path.dart' as path;
import 'package:url_launcher/url_launcher.dart';
import '../../../../core/services/auth_service.dart';
import 'pdf_viewer_page.dart';
/// Página de Materiais do Professor
/// Tela dedicada para upload e gestão de materiais para a IA
@@ -78,10 +79,12 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
return Scaffold(
appBar: AppBar(
title: const Text(
'Materiais da Disciplina',
'Gerenciamento de conteudo',
style: TextStyle(fontWeight: FontWeight.bold),
),
elevation: 0,
backgroundColor: const Color(0xFF82C9BD),
foregroundColor: Colors.white,
),
body: Container(
decoration: BoxDecoration(
@@ -116,10 +119,12 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
child: Scaffold(
appBar: AppBar(
title: const Text(
'Materiais da Disciplina',
'Gerenciamento de conteudo',
style: TextStyle(fontWeight: FontWeight.bold),
),
elevation: 0,
backgroundColor: const Color(0xFF82C9BD),
foregroundColor: Colors.white,
bottom: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight + 60),
child: Column(
@@ -296,17 +301,32 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
final fileName =
material['fileName'] ?? 'Ficheiro sem nome';
final createdAt = material['createdAt'] as Timestamp?;
final extension = path.extension(fileName).toLowerCase();
final fileType = extension == '.pdf'
? 'pdf'
: (extension == '.jpg' ||
extension == '.jpeg' ||
extension == '.png')
? 'image'
: 'other';
final mimeType = material['mimeType'] as String?;
final url = material['url'] as String?;
// Determine file type from MIME type, fallback to extension
String fileType;
if (mimeType != null) {
if (mimeType == 'application/pdf') {
fileType = 'pdf';
} else if (mimeType.startsWith('image/')) {
fileType = 'image';
} else {
fileType = 'other';
}
} else {
// Fallback to extension for old files without MIME type
final extension = path.extension(fileName).toLowerCase();
fileType = extension == '.pdf'
? 'pdf'
: (extension == '.jpg' ||
extension == '.jpeg' ||
extension == '.png')
? 'image'
: 'other';
}
final docId = materials[index].id;
final url = material['url'] as String?;
return _buildMaterialCard(
docId: docId,
@@ -699,7 +719,16 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
.child('materials')
.child(cleanFileName);
await ref.putFile(File(filePath));
// Set content type based on file type parameter
final metadata = SettableMetadata(
contentType: fileType == 'pdf'
? 'application/pdf'
: fileType == 'image'
? 'image/jpeg'
: 'application/octet-stream',
);
await ref.putFile(File(filePath), metadata);
final downloadUrl = await ref.getDownloadURL();
// Criar documento no Firestore
@@ -707,6 +736,11 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
'teacherId': uid,
'fileName': cleanFileName,
'url': downloadUrl,
'mimeType': fileType == 'pdf'
? 'application/pdf'
: fileType == 'image'
? 'image/jpeg'
: 'application/octet-stream',
'createdAt': FieldValue.serverTimestamp(),
};
if (classId != null && classId.isNotEmpty) {
@@ -835,31 +869,6 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
);
}
Future<void> _openFile(String? url, String fileName) async {
if (url == null || url.isEmpty) {
_showErrorSnackBar('URL do ficheiro não disponível');
return;
}
try {
print('Opening file: $fileName');
print('URL: $url');
final uri = Uri.parse(url);
final launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!launched) {
_showErrorSnackBar('Não foi possível abrir o ficheiro');
}
} catch (e) {
print('Error opening file: $e');
_showErrorSnackBar('Erro ao abrir ficheiro: $e');
}
}
Future<void> _downloadFile(String? url, String fileName) async {
if (url == null || url.isEmpty) {
_showErrorSnackBar('URL do ficheiro não disponível');
@@ -887,6 +896,20 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
}
}
Future<void> _viewInApp(String? url, String fileName) async {
if (url == null || url.isEmpty) {
_showErrorSnackBar('URL do ficheiro não disponível');
return;
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PdfViewerPage(url: url, fileName: fileName),
),
);
}
Widget _buildMaterialCard({
required String docId,
required String fileName,
@@ -938,15 +961,16 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
),
child: Icon(iconData, color: iconColor, size: 28),
),
title: Text(
fileName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface,
title: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Text(
fileName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface,
),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
formattedDate,
@@ -962,7 +986,7 @@ class _TeacherMaterialsPageState extends State<TeacherMaterialsPage> {
icon: const Icon(Icons.visibility_outlined, color: Colors.blue),
tooltip: 'Ver',
constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
onPressed: () => _openFile(url, fileName),
onPressed: () => _viewInApp(url, fileName),
),
IconButton(
icon: const Icon(Icons.download_outlined, color: Colors.green),