From f1a094979f54cb25948609a1266211c9dd6b0e91 Mon Sep 17 00:00:00 2001 From: 240403 <240403@epvc.pt> Date: Sun, 24 May 2026 16:48:18 +0100 Subject: [PATCH] aba de turmas dos professores melhorada com tudo oque era suposto --- .../pages/class_students_page.dart | 893 +++++++++++++++--- 1 file changed, 737 insertions(+), 156 deletions(-) diff --git a/lib/features/classes/presentation/pages/class_students_page.dart b/lib/features/classes/presentation/pages/class_students_page.dart index cba3d7e..13e35c0 100644 --- a/lib/features/classes/presentation/pages/class_students_page.dart +++ b/lib/features/classes/presentation/pages/class_students_page.dart @@ -1,7 +1,10 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; +import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../../../../core/services/auth_service.dart'; +import '../../../../core/theme/app_theme_extension.dart'; /// Página para visualizar os alunos de uma turma específica class ClassStudentsPage extends StatefulWidget { @@ -21,10 +24,13 @@ class ClassStudentsPage extends StatefulWidget { class _ClassStudentsPageState extends State { bool _isCheckingAccess = true; bool _accessGranted = false; + String _currentClassName = ''; + String? _classCode; @override void initState() { super.initState(); + _currentClassName = widget.className; _verifyOwnership(); } @@ -53,15 +59,254 @@ class _ClassStudentsPageState extends State { .get(); final teacherId = classDoc.data()?['teacherId'] as String?; + final code = classDoc.data()?['code'] as String?; + setState(() { _isCheckingAccess = false; _accessGranted = classDoc.exists && teacherId == currentUser.uid; + _classCode = code ?? '----'; }); } + Future _updateClassName(String newName) async { + try { + await FirebaseFirestore.instance + .collection('classes') + .doc(widget.classId) + .update({'name': newName}); + + setState(() { + _currentClassName = newName; + }); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + const Icon(Icons.check_circle, color: Colors.white), + const SizedBox(width: 12), + const Text('Nome da turma atualizado com sucesso'), + ], + ), + backgroundColor: Colors.green, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + duration: const Duration(seconds: 3), + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + const Icon(Icons.error_outline, color: Colors.white), + const SizedBox(width: 12), + Text('Erro ao atualizar nome: $e'), + ], + ), + backgroundColor: Colors.red, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + duration: const Duration(seconds: 4), + ), + ); + } + } + } + + Future _deleteClass() async { + try { + // Delete all enrollments first + final enrollmentsSnapshot = await FirebaseFirestore.instance + .collection('enrollments') + .where('classId', isEqualTo: widget.classId) + .get(); + + final batch = FirebaseFirestore.instance.batch(); + for (final doc in enrollmentsSnapshot.docs) { + batch.delete(doc.reference); + } + await batch.commit(); + + // Delete the class + await FirebaseFirestore.instance + .collection('classes') + .doc(widget.classId) + .delete(); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + const Icon(Icons.check_circle, color: Colors.white), + const SizedBox(width: 12), + const Text('Turma eliminada com sucesso'), + ], + ), + backgroundColor: Colors.green, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + duration: const Duration(seconds: 3), + ), + ); + context.pop(); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + const Icon(Icons.error_outline, color: Colors.white), + const SizedBox(width: 12), + Text('Erro ao eliminar turma: $e'), + ], + ), + backgroundColor: Colors.red, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + duration: const Duration(seconds: 4), + ), + ); + } + } + } + + void _showEditClassNameDialog() { + final textController = TextEditingController(text: _currentClassName); + + showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + title: Row( + children: [ + Icon(Icons.edit, color: Theme.of(context).colorScheme.primary), + const SizedBox(width: 8), + const Text('Editar Nome'), + ], + ), + content: TextField( + controller: textController, + decoration: InputDecoration( + labelText: 'Nome da Turma', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + prefixIcon: const Icon(Icons.school), + ), + autofocus: true, + maxLength: 50, + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Cancelar'), + ), + FilledButton( + onPressed: () { + final newName = textController.text.trim(); + if (newName.isNotEmpty && newName != _currentClassName) { + Navigator.of(context).pop(); + _updateClassName(newName); + } + }, + child: const Text('Guardar'), + ), + ], + ), + ); + } + + void _showDeleteClassDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + title: Row( + children: [ + Icon(Icons.warning, color: Theme.of(context).colorScheme.error), + const SizedBox(width: 8), + const Text('Eliminar Turma'), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tens a certeza que desejas eliminar a turma "$_currentClassName"?', + style: const TextStyle(fontSize: 14), + ), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.error.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Theme.of(context).colorScheme.error.withValues(alpha: 0.3), + ), + ), + child: Row( + children: [ + Icon( + Icons.warning_amber, + color: Theme.of(context).colorScheme.error, + size: 20, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Esta ação não pode ser desfeita. Todos os alunos serão removidos.', + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.error, + ), + ), + ), + ], + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Cancelar'), + ), + FilledButton( + onPressed: () { + Navigator.of(context).pop(); + _deleteClass(); + }, + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.error, + foregroundColor: Colors.white, + ), + child: const Text('Eliminar'), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; + final themeExtras = AppThemeExtras.of(context); if (_isCheckingAccess) { return Scaffold( @@ -73,12 +318,6 @@ class _ClassStudentsPageState extends State { if (!_accessGranted) { return Scaffold( backgroundColor: cs.surface, - appBar: AppBar( - backgroundColor: cs.surface, - foregroundColor: cs.onSurface, - elevation: 0, - title: const Text('Acesso Negado'), - ), body: Center( child: Padding( padding: const EdgeInsets.all(32.0), @@ -109,177 +348,510 @@ class _ClassStudentsPageState extends State { } return Scaffold( - backgroundColor: cs.surface, - appBar: AppBar( - backgroundColor: cs.surface, - foregroundColor: cs.onSurface, - elevation: 0, - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.className, - style: TextStyle( - color: cs.onSurface, - fontSize: 18, - fontWeight: FontWeight.bold, + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: themeExtras.dashboardBackgroundGradient, + stops: themeExtras.dashboardGradientStops, + ), + ), + child: SafeArea( + top: false, + child: Column( + children: [ + // Custom AppBar + _buildAppBar(cs), + // Main Content + Expanded( + child: StreamBuilder( + stream: FirebaseFirestore.instance + .collection('enrollments') + .where('classId', isEqualTo: widget.classId) + .orderBy('joinedAt', descending: true) + .snapshots(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: CircularProgressIndicator(color: cs.primary), + ); + } + + if (snapshot.hasError) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.error_outline, + size: 48, + color: cs.onSurfaceVariant, + ), + const SizedBox(height: 16), + Text( + 'Erro ao carregar alunos', + style: TextStyle( + color: cs.onSurfaceVariant, + fontSize: 16, + ), + ), + ], + ), + ); + } + + final enrollments = snapshot.data?.docs ?? []; + + if (enrollments.isEmpty) { + return _buildEmptyState(cs); + } + + return _buildStudentsList(cs, enrollments); + }, + ), ), - ), - Text( - 'Alunos Matriculados', - style: TextStyle( - color: cs.onSurfaceVariant, - fontSize: 13, - fontWeight: FontWeight.w400, - ), - ), - ], + ], + ), ), ), - body: StreamBuilder( - stream: FirebaseFirestore.instance - .collection('enrollments') - .where('classId', isEqualTo: widget.classId) - .orderBy('joinedAt', descending: true) - .snapshots(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return Center(child: CircularProgressIndicator(color: cs.primary)); - } + ); + } - if (snapshot.hasError) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.error_outline, - size: 48, - color: cs.onSurfaceVariant, - ), - const SizedBox(height: 16), - Text( - 'Erro ao carregar alunos', - style: TextStyle(color: cs.onSurfaceVariant, fontSize: 16), - ), - ], - ), - ); - } - - final enrollments = snapshot.data?.docs ?? []; - - if (enrollments.isEmpty) { - return Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.people_outline, - size: 64, - color: cs.onSurfaceVariant.withValues(alpha: 0.4), - ), - const SizedBox(height: 24), - Text( - 'Nenhum aluno entrou nesta turma ainda.', - style: TextStyle( - color: cs.onSurfaceVariant, - fontSize: 16, - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 8), - Text( - 'Partilha o código da turma para os alunos se juntarem.', - style: TextStyle( - color: cs.onSurfaceVariant.withValues(alpha: 0.7), - fontSize: 13, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ); - } - - return ListView.separated( - padding: const EdgeInsets.all(16), - itemCount: enrollments.length, - separatorBuilder: (_, __) => const SizedBox(height: 12), - itemBuilder: (context, index) { - final enrollment = - enrollments[index].data() as Map; - final studentName = - enrollment['studentName'] as String? ?? 'Aluno sem nome'; - final joinedAt = enrollment['joinedAt'] as Timestamp?; - final enrollmentId = enrollments[index].id; - - return Container( + Widget _buildAppBar(ColorScheme cs) { + return Container( + padding: const EdgeInsets.only( + left: 16, + right: 16, + top: 52, + bottom: 16, + ), + child: Column( + children: [ + // Top Row with Back and Actions + Row( + children: [ + Container( decoration: BoxDecoration( - color: cs.surface, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: cs.outline.withValues(alpha: 0.15)), - boxShadow: [ - BoxShadow( - color: cs.shadow.withValues(alpha: 0.05), - blurRadius: 8, - offset: const Offset(0, 2), + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + ), + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () => context.pop(), + tooltip: 'Voltar', + ), + ), + const Spacer(), + // Edit Button + Container( + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + ), + child: IconButton( + icon: const Icon(Icons.edit, color: Colors.white), + onPressed: _showEditClassNameDialog, + tooltip: 'Editar nome', + ), + ), + const SizedBox(width: 8), + // Delete Button + Container( + decoration: BoxDecoration( + color: Colors.red.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + ), + child: IconButton( + icon: const Icon(Icons.delete_outline, color: Colors.white), + onPressed: _showDeleteClassDialog, + tooltip: 'Eliminar turma', + ), + ), + ], + ), + const SizedBox(height: 20), + // Class Info Card + Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.white.withValues(alpha: 0.2), + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.school, + color: Colors.white, + size: 28, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _currentClassName, + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + Text( + 'Código: $_classCode', + style: TextStyle( + color: Colors.white.withValues(alpha: 0.8), + fontSize: 14, + ), + ), + ], + ), ), ], ), - child: ListTile( - contentPadding: const EdgeInsets.symmetric( + const SizedBox(height: 16), + // Stats Row + Container( + padding: const EdgeInsets.symmetric( horizontal: 16, - vertical: 8, + vertical: 12, ), - leading: Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: cs.primary.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(12), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: StreamBuilder( + stream: FirebaseFirestore.instance + .collection('enrollments') + .where('classId', isEqualTo: widget.classId) + .snapshots(), + builder: (context, snapshot) { + final count = snapshot.data?.docs.length ?? 0; + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.people, + color: Colors.white, + size: 20, + ), + const SizedBox(width: 8), + Text( + '$count ${count == 1 ? 'aluno matriculado' : 'alunos matriculados'}', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ], + ); + }, + ), + ), + ], + ), + ).animate().fadeIn( + duration: const Duration(milliseconds: 400), + curve: Curves.easeOut, + ), + ], + ), + ); + } + + Widget _buildEmptyState(ColorScheme cs) { + return SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 40), + Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: cs.surface, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: cs.shadow.withValues(alpha: 0.08), + blurRadius: 20, + offset: const Offset(0, 8), + ), + ], + ), + child: Column( + children: [ + Icon( + Icons.people_outline, + size: 80, + color: cs.primary.withValues(alpha: 0.5), + ), + const SizedBox(height: 24), + Text( + 'Nenhum aluno entrou nesta turma ainda.', + style: TextStyle( + color: cs.onSurface, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Text( + 'Partilha o código da turma para os alunos se juntarem.', + style: TextStyle( + color: cs.onSurfaceVariant, + fontSize: 14, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + decoration: BoxDecoration( + color: cs.primary.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: cs.primary.withValues(alpha: 0.3), ), - child: Icon(Icons.person, color: cs.primary, size: 24), ), - title: Text( - studentName, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.copy, color: cs.primary, size: 18), + const SizedBox(width: 8), + Text( + 'Código: $_classCode', + style: TextStyle( + color: cs.primary, + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ).animate().fadeIn( + duration: const Duration(milliseconds: 400), + curve: Curves.easeOut, + ).then(delay: const Duration(milliseconds: 100)), + ], + ), + ); + } + + Widget _buildStudentsList( + ColorScheme cs, + List enrollments, + ) { + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Section Title + Container( + margin: const EdgeInsets.only(bottom: 16, left: 8), + child: Row( + children: [ + Icon( + Icons.people, + color: cs.onSurface, + size: 20, + ), + const SizedBox(width: 8), + Text( + 'Alunos Matriculados', + style: TextStyle( + color: cs.onSurface, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: cs.primary.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '${enrollments.length}', style: TextStyle( - color: cs.onSurface, - fontSize: 15, - fontWeight: FontWeight.w600, + color: cs.primary, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - subtitle: Padding( - padding: const EdgeInsets.only(top: 4), + ), + ], + ), + ), + // Students List + ...enrollments.asMap().entries.map((entry) { + final index = entry.key; + final enrollment = entry.value.data() as Map; + final studentName = + enrollment['studentName'] as String? ?? 'Aluno sem nome'; + final joinedAt = enrollment['joinedAt'] as Timestamp?; + final enrollmentId = entry.value.id; + + return _buildStudentCard( + cs, + studentName, + joinedAt, + enrollmentId, + index, + ); + }), + const SizedBox(height: 24), + ], + ), + ); + } + + Widget _buildStudentCard( + ColorScheme cs, + String studentName, + Timestamp? joinedAt, + String enrollmentId, + int index, + ) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + color: cs.surface, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: cs.shadow.withValues(alpha: 0.06), + blurRadius: 12, + offset: const Offset(0, 4), + ), + ], + ), + child: Material( + color: Colors.transparent, + borderRadius: BorderRadius.circular(16), + child: InkWell( + borderRadius: BorderRadius.circular(16), + onTap: null, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + // Avatar + Container( + width: 52, + height: 52, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + cs.primary.withValues(alpha: 0.8), + cs.primary.withValues(alpha: 0.4), + ], + ), + borderRadius: BorderRadius.circular(14), + ), + child: Center( child: Text( - joinedAt != null - ? 'Entrou em ${_formatDate(joinedAt.toDate())}' - : 'Data desconhecida', - style: TextStyle( - color: cs.onSurfaceVariant, - fontSize: 13, + studentName.isNotEmpty + ? studentName[0].toUpperCase() + : '?', + style: const TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.bold, ), ), ), - trailing: IconButton( - icon: Icon(Icons.delete_outline, color: cs.error), + ), + const SizedBox(width: 16), + // Info + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + studentName, + style: TextStyle( + color: cs.onSurface, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + Text( + joinedAt != null + ? 'Entrou em ${_formatDate(joinedAt.toDate())}' + : 'Data desconhecida', + style: TextStyle( + color: cs.onSurfaceVariant, + fontSize: 13, + ), + ), + ], + ), + ), + // Delete Button + Container( + decoration: BoxDecoration( + color: cs.error.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(10), + ), + child: IconButton( + icon: Icon(Icons.delete_outline, color: cs.error, size: 20), onPressed: () => _showRemoveStudentDialog( context, enrollmentId, studentName, ), tooltip: 'Remover aluno', + padding: const EdgeInsets.all(10), + constraints: const BoxConstraints(), ), ), - ); - }, - ); - }, + ], + ), + ), + ), ), - ); + ).animate().fadeIn( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + ).then(delay: Duration(milliseconds: index * 50)); } String _formatDate(DateTime date) { @@ -294,19 +866,28 @@ class _ClassStudentsPageState extends State { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Remover Aluno'), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + title: Row( + children: [ + Icon(Icons.person_remove, color: Theme.of(context).colorScheme.error), + const SizedBox(width: 8), + const Text('Remover Aluno'), + ], + ), content: Text( - 'Tem a certeza que deseja remover $studentName desta turma?', + 'Tens a certeza que desejas remover $studentName desta turma?', + style: const TextStyle(fontSize: 14), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancelar'), ), - TextButton( + FilledButton( onPressed: () => Navigator.of(context).pop(true), - style: TextButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.error, + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.error, + foregroundColor: Colors.white, ), child: const Text('Remover'), ), @@ -326,7 +907,7 @@ class _ClassStudentsPageState extends State { SnackBar( content: Row( children: [ - Icon(Icons.check_circle, color: Colors.white), + const Icon(Icons.check_circle, color: Colors.white), const SizedBox(width: 12), const Text('Aluno removido com sucesso'), ], @@ -346,7 +927,7 @@ class _ClassStudentsPageState extends State { SnackBar( content: Row( children: [ - Icon(Icons.error_outline, color: Colors.white), + const Icon(Icons.error_outline, color: Colors.white), const SizedBox(width: 12), Text('Erro ao remover aluno: $e'), ],