From 85157b86730483a953faa8bf19bd694913b4664b Mon Sep 17 00:00:00 2001 From: 240403 <240403@epvc.pt> Date: Sun, 10 May 2026 15:10:26 +0100 Subject: [PATCH] =?UTF-8?q?cria=C3=A7=C3=A3o=20da=20tela=20home=20dos=20pr?= =?UTF-8?q?ofessores=20e=20aniquila=C3=A7=C3=A3o=20do=20placeholder=20da?= =?UTF-8?q?=20home=20dos=20professores=20(talzes=20o=20"j=C3=A1=20tenho=20?= =?UTF-8?q?conta"=20desapare=C3=A7a,=20talvez=20nao,=20que=20seja=20oq=20d?= =?UTF-8?q?eus=20quiser)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/PROJECT_PROGRESS.md | 10 +- .../pages/role_selection_page.dart | 24 +- .../pages/teacher_dashboard_page.dart | 159 +++++++- .../teacher_analytics_preview_widget.dart | 309 ++++++++++++++ .../widgets/teacher_hero_widget.dart | 326 +++++++++++++++ .../widgets/teacher_quick_actions_widget.dart | 376 ++++++++++++++++++ 6 files changed, 1160 insertions(+), 44 deletions(-) create mode 100644 lib/features/dashboard/presentation/widgets/teacher_analytics_preview_widget.dart create mode 100644 lib/features/dashboard/presentation/widgets/teacher_hero_widget.dart create mode 100644 lib/features/dashboard/presentation/widgets/teacher_quick_actions_widget.dart diff --git a/docs/PROJECT_PROGRESS.md b/docs/PROJECT_PROGRESS.md index 9f8b295..755f828 100644 --- a/docs/PROJECT_PROGRESS.md +++ b/docs/PROJECT_PROGRESS.md @@ -192,11 +192,11 @@ This document tracks the overall progress of the AI Study Assistant project deve -### **📊 Dashboard System (0%)** +### **📊 Dashboard System (50%)** -- [ ] Student dashboard +- [x] Student dashboard -- [ ] Teacher dashboard +- [x] Teacher dashboard - [ ] Analytics display @@ -204,7 +204,7 @@ This document tracks the overall progress of the AI Study Assistant project deve - [ ] Performance metrics -- [ ] Quick actions +- [x] Quick actions @@ -452,7 +452,7 @@ This document tracks the overall progress of the AI Study Assistant project deve 3. **Add role-based routing** after login -4. **Create basic dashboard** placeholder +4. ~~**Create basic dashboard** placeholder~~ ✅ **Student & Teacher dashboards implemented** diff --git a/lib/features/auth/presentation/pages/role_selection_page.dart b/lib/features/auth/presentation/pages/role_selection_page.dart index 76f68b3..f2ec963 100644 --- a/lib/features/auth/presentation/pages/role_selection_page.dart +++ b/lib/features/auth/presentation/pages/role_selection_page.dart @@ -278,28 +278,6 @@ class _RoleSelectionPageState extends State { ), const SizedBox(height: 32), - - // Login link - GestureDetector( - onTap: _selectedRole != null ? _handleGoToLogin : null, - child: Text( - 'Já tenho conta', - style: TextStyle( - color: _selectedRole != null - ? AppColors.primaryBlue - : Colors.grey, - fontWeight: FontWeight.w500, - decoration: TextDecoration.underline, - ), - ), - ) - .animate() - .fadeIn( - duration: const Duration(milliseconds: 800), - delay: const Duration(milliseconds: 1400), - ), - - const SizedBox(height: 32), ], ), ), @@ -432,4 +410,4 @@ class _RoleSelectionPageState extends State { context.go('/signup?role=$_selectedRole'); } } -} +} \ No newline at end of file diff --git a/lib/features/dashboard/presentation/pages/teacher_dashboard_page.dart b/lib/features/dashboard/presentation/pages/teacher_dashboard_page.dart index 6709c35..73f362e 100644 --- a/lib/features/dashboard/presentation/pages/teacher_dashboard_page.dart +++ b/lib/features/dashboard/presentation/pages/teacher_dashboard_page.dart @@ -1,26 +1,153 @@ import 'package:flutter/material.dart'; -import '../../../../core/theme/app_colors.dart'; +import 'package:go_router/go_router.dart'; +import '../../../../core/services/auth_service.dart'; +import '../widgets/teacher_hero_widget.dart'; +import '../widgets/teacher_quick_actions_widget.dart'; +import '../widgets/teacher_analytics_preview_widget.dart'; -class TeacherDashboardPage extends StatelessWidget { +class TeacherDashboardPage extends StatefulWidget { const TeacherDashboardPage({super.key}); + @override + State createState() => _TeacherDashboardPageState(); +} + +class _TeacherDashboardPageState extends State { + String _userName = 'Professor'; + + @override + void initState() { + super.initState(); + _loadUserData(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _loadUserData(); + } + + Future _loadUserData() async { + try { + final user = AuthService.currentUser; + if (user != null) { + print('DEBUG: Loading teacher data for dashboard'); + print('DEBUG: User email: ${user.email}'); + print('DEBUG: User displayName before reload: ${user.displayName}'); + + await user.reload(); + + final updatedUser = AuthService.currentUser; + if (updatedUser != null) { + print( + 'DEBUG: User displayName after reload: ${updatedUser.displayName}', + ); + + String displayName = updatedUser.displayName ?? ''; + print('DEBUG: Initial displayName value: "$displayName"'); + + if (displayName.isEmpty && updatedUser.email != null) { + displayName = updatedUser.email!.split('@')[0]; + print('DEBUG: Extracted name from email: "$displayName"'); + } + if (displayName.isEmpty) { + displayName = 'Professor'; + print('DEBUG: Using fallback "Professor"'); + } + + print('DEBUG: Final displayName to use: "$displayName"'); + setState(() { + _userName = displayName; + }); + } + } + } catch (e) { + print('DEBUG: Error loading user data: $e'); + } + } + @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: AppColors.background, - appBar: AppBar( - title: const Text('Teacher Dashboard'), - backgroundColor: AppColors.surface, - foregroundColor: AppColors.textPrimary, - elevation: 0, - ), - body: const Center( - child: Text( - 'Teacher Dashboard - Coming Soon', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.textPrimary, + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xFF82C9BD), + Color(0xFF7BA89C), + Color(0xFFF68D2D), + Color(0xFFF8F9FA), + ], + stops: [0.0, 0.2, 0.6, 1.0], + ), + ), + child: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header with logout + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Bem-vindo, $_userName!', + style: const TextStyle( + color: Colors.white, + fontSize: 28, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + const Text( + 'Painel de Gestão de Conteúdo', + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w300, + ), + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.logout, color: Colors.white), + onPressed: () async { + await AuthService.signOut(); + if (mounted) { + context.go('/login'); + } + }, + tooltip: 'Sair', + ), + ], + ), + const SizedBox(height: 32), + + // Hero Section - Class Overview + TeacherHeroWidget(userName: _userName), + + const SizedBox(height: 24), + + // Quick Actions Section + const TeacherQuickActionsWidget(), + + const SizedBox(height: 24), + + // Analytics Preview Section + const TeacherAnalyticsPreviewWidget(), + + const SizedBox(height: 40), + ], + ), + ), ), ), ), diff --git a/lib/features/dashboard/presentation/widgets/teacher_analytics_preview_widget.dart b/lib/features/dashboard/presentation/widgets/teacher_analytics_preview_widget.dart new file mode 100644 index 0000000..fe24639 --- /dev/null +++ b/lib/features/dashboard/presentation/widgets/teacher_analytics_preview_widget.dart @@ -0,0 +1,309 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; +import '../../../../core/services/auth_service.dart'; + +/// Analytics preview section for teacher dashboard +class TeacherAnalyticsPreviewWidget extends StatelessWidget { + const TeacherAnalyticsPreviewWidget({super.key}); + + @override + Widget build(BuildContext context) { + final user = AuthService.currentUser; + final userName = user?.displayName ?? 'Professor'; + final userEmail = user?.email ?? ''; + + return Container( + margin: const EdgeInsets.only(top: 24), + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE2E8F0)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Profile Header + Row( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFF82C9BD), Color(0xFF6BA8A0)], + ), + borderRadius: BorderRadius.circular(24), + ), + child: const Icon( + Icons.school, + color: Colors.white, + size: 24, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + userName, + style: const TextStyle( + color: Color(0xFF2D3748), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 2), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + userEmail, + style: const TextStyle( + color: Color(0xFF718096), + fontSize: 14, + ), + ), + if (userEmail.length > 20) ...[ + const SizedBox(width: 8), + const Icon( + Icons.more_horiz, + color: Color(0xFF718096), + size: 16, + ), + ], + ], + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFFF68D2D).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.settings, + color: Color(0xFFF68D2D), + size: 20, + ), + ), + ], + ), + const SizedBox(height: 20), + + // Quick Stats Row + Row( + children: [ + _buildQuickStat( + icon: Icons.check_circle, + label: 'Alunos Ativos', + value: '18/24', + color: const Color(0xFF82C9BD), + ), + const SizedBox(width: 12), + _buildQuickStat( + icon: Icons.warning_amber, + label: 'Precisam Apoio', + value: '3', + color: const Color(0xFFF68D2D), + ), + const SizedBox(width: 12), + _buildQuickStat( + icon: Icons.emoji_events, + label: 'Média Turma', + value: '72%', + color: const Color(0xFF6BA8A0), + ), + ], + ), + const SizedBox(height: 20), + + // Top Performing Students Preview + Row( + children: [ + const Icon( + Icons.leaderboard, + color: Color(0xFFF68D2D), + size: 20, + ), + const SizedBox(width: 8), + const Text( + 'Melhores Desempenhos', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 12), + + // Student List Preview + _buildStudentPerformanceItem('Ana Silva', 95, const Color(0xFF4CAF50)), + const SizedBox(height: 8), + _buildStudentPerformanceItem('João Costa', 88, const Color(0xFF82C9BD)), + const SizedBox(height: 8), + _buildStudentPerformanceItem('Maria Santos', 82, const Color(0xFF82C9BD)), + const SizedBox(height: 8), + _buildStudentPerformanceItem('Pedro Lima', 45, const Color(0xFFF68D2D)), + + const SizedBox(height: 20), + + // Content Quality Alert + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE2E8F0)), + ), + child: Row( + children: [ + const Icon( + Icons.info_outline, + color: Color(0xFF82C9BD), + size: 20, + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Qualidade do Conteúdo', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 2), + Text( + '12 conteúdos verificados • 2 pendentes de revisão', + style: const TextStyle( + color: Color(0xFF718096), + fontSize: 12, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ) + .animate() + .slideY( + duration: const Duration(milliseconds: 800), + curve: Curves.easeOut, + ) + .then(delay: const Duration(milliseconds: 400)); + } + + Widget _buildQuickStat({ + required IconData icon, + required String label, + required String value, + required Color color, + }) { + return Expanded( + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: color.withOpacity(0.3), width: 1), + ), + child: Column( + children: [ + Icon(icon, color: color, size: 20), + const SizedBox(height: 6), + Text( + value, + style: TextStyle( + color: color, + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 2), + Text( + label, + style: TextStyle( + color: color.withOpacity(0.8), + fontSize: 10, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } + + Widget _buildStudentPerformanceItem(String name, int score, Color color) { + return Row( + children: [ + Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + ), + child: Center( + child: Text( + name.split(' ').map((n) => n[0]).take(2).join(), + style: TextStyle( + color: color, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Text( + name, + style: const TextStyle( + color: Color(0xFF4A5568), + fontSize: 14, + ), + ), + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + '$score%', + style: TextStyle( + color: color, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + } +} diff --git a/lib/features/dashboard/presentation/widgets/teacher_hero_widget.dart b/lib/features/dashboard/presentation/widgets/teacher_hero_widget.dart new file mode 100644 index 0000000..3711a85 --- /dev/null +++ b/lib/features/dashboard/presentation/widgets/teacher_hero_widget.dart @@ -0,0 +1,326 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; + +/// Hero section for teacher dashboard showing class overview +class TeacherHeroWidget extends StatelessWidget { + final String userName; + final int totalStudents; + final int activeQuizzes; + final int uploadedContent; + final double classAverageProgress; + + const TeacherHeroWidget({ + super.key, + required this.userName, + this.totalStudents = 24, + this.activeQuizzes = 3, + this.uploadedContent = 12, + this.classAverageProgress = 0.72, + }); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.only(bottom: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Visão Geral da Turma', + style: TextStyle( + color: const Color(0xFF2D3748), + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + Text( + 'Acompanhe o progresso dos seus alunos', + style: TextStyle( + color: const Color(0xFF718096), + fontSize: 16, + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: const Color(0xFFF68D2D), + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.people, + color: Colors.white, + size: 16, + ), + const SizedBox(width: 4), + Text( + '$totalStudents alunos', + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 20), + + // Main Class Progress Card + Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + const Color(0xFF82C9BD), + const Color(0xFF6BA8A0), + ], + ), + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Overall Progress + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Progresso Médio da Turma', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + Text( + '${(classAverageProgress * 100).toInt()}%', + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 16), + + // Progress Bar + Container( + height: 12, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.3), + borderRadius: BorderRadius.circular(6), + ), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: classAverageProgress, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Colors.white, Color(0xFFF8F9FA)], + ), + borderRadius: BorderRadius.circular(6), + ), + ), + ), + ), + const SizedBox(height: 20), + + // Stats Grid + Row( + children: [ + Expanded( + child: _buildStatCard( + icon: Icons.quiz, + value: '$activeQuizzes', + label: 'Quizzes Ativos', + ), + ), + const SizedBox(width: 12), + Expanded( + child: _buildStatCard( + icon: Icons.upload_file, + value: '$uploadedContent', + label: 'Conteúdos', + ), + ), + ], + ), + ], + ), + ).animate().scale( + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + ), + + const SizedBox(height: 20), + + // Recent Activity + Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE2E8F0)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.trending_up, + color: Color(0xFFF68D2D), + size: 20, + ), + const SizedBox(width: 8), + const Text( + 'Atividade Recente', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 12), + _buildActivityItem( + '15 alunos completaram o quiz de Derivadas', + 'Hoje, 14:30', + const Color(0xFF82C9BD), + ), + const SizedBox(height: 8), + _buildActivityItem( + 'Novo conteúdo: Regra da Cadeia', + 'Ontem, 09:15', + const Color(0xFFF68D2D), + ), + const SizedBox(height: 8), + _buildActivityItem( + '3 alunos precisam de apoio em Limites', + 'Ontem, 16:45', + const Color(0xFFE53E3E), + ), + ], + ), + ).animate().slideX( + duration: const Duration(milliseconds: 800), + curve: Curves.easeOut, + ).then(delay: const Duration(milliseconds: 200)), + ], + ), + ); + } + + Widget _buildStatCard({ + required IconData icon, + required String value, + required String label, + }) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.white.withOpacity(0.3), + width: 1, + ), + ), + child: Column( + children: [ + Icon(icon, color: Colors.white, size: 24), + const SizedBox(height: 8), + Text( + value, + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + Text( + label, + style: const TextStyle( + color: Colors.white, + fontSize: 12, + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + Widget _buildActivityItem(String text, String time, Color color) { + return Row( + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + text, + style: const TextStyle( + color: Color(0xFF4A5568), + fontSize: 14, + ), + ), + const SizedBox(height: 2), + Text( + time, + style: const TextStyle( + color: Color(0xFF718096), + fontSize: 12, + ), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/features/dashboard/presentation/widgets/teacher_quick_actions_widget.dart b/lib/features/dashboard/presentation/widgets/teacher_quick_actions_widget.dart new file mode 100644 index 0000000..8776dc8 --- /dev/null +++ b/lib/features/dashboard/presentation/widgets/teacher_quick_actions_widget.dart @@ -0,0 +1,376 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; +import 'package:go_router/go_router.dart'; + +/// Quick access cards for teacher actions +class TeacherQuickActionsWidget extends StatelessWidget { + const TeacherQuickActionsWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Ações Rápidas', + style: TextStyle( + color: const Color(0xFF2D3748), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + + // Primary Actions Row + Row( + children: [ + // Upload Content Card (Primary) + Expanded(flex: 3, child: _buildUploadContentCard(context)), + const SizedBox(width: 16), + // Create Quiz Card (Secondary) + Expanded(flex: 2, child: _buildCreateQuizCard(context)), + ], + ), + const SizedBox(height: 16), + + // Secondary Actions Row + Row( + children: [ + // Manage Students Card + Expanded(child: _buildManageStudentsCard(context)), + const SizedBox(width: 16), + // View Analytics Card + Expanded(child: _buildViewAnalyticsCard(context)), + ], + ), + ], + ) + .animate() + .slideY( + duration: const Duration(milliseconds: 800), + curve: Curves.easeOut, + ) + .then(delay: const Duration(milliseconds: 200)); + } + + Widget _buildUploadContentCard(BuildContext context) { + return Container( + height: 150, + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFF82C9BD), Color(0xFF6BA8A0)], + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: const Color(0xFF82C9BD).withOpacity(0.3), + blurRadius: 15, + offset: const Offset(0, 8), + ), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => context.go('/teacher/upload'), + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(7), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.upload_file, + color: Colors.white, + size: 24, + ), + ), + const Spacer(), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), + decoration: BoxDecoration( + color: const Color(0xFFF68D2D), + borderRadius: BorderRadius.circular(12), + ), + child: const Text( + 'NOVO', + style: TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Upload Conteúdo', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'PDFs, textos, imagens', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.white, + fontSize: 12, + height: 1.2, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ) + .animate() + .scale( + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + ) + .then(delay: const Duration(milliseconds: 100)); + } + + Widget _buildCreateQuizCard(BuildContext context) { + return Container( + height: 150, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE2E8F0), width: 1), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => context.go('/teacher/quiz/create'), + child: Padding( + padding: const EdgeInsets.all(14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: const Color(0xFFF68D2D).withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.quiz, + color: Color(0xFFF68D2D), + size: 24, + ), + ), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Criar Quiz', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + Text( + 'Avaliações', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Color(0xFF718096), + fontSize: 12, + height: 1.2, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ) + .animate() + .scale( + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + ) + .then(delay: const Duration(milliseconds: 200)); + } + + Widget _buildManageStudentsCard(BuildContext context) { + return Container( + height: 120, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE2E8F0), width: 1), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => context.go('/teacher/students'), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF82C9BD).withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.people, + color: Color(0xFF82C9BD), + size: 20, + ), + ), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Gerir Alunos', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'Acesso e permissões', + style: TextStyle( + color: Color(0xFF718096), + fontSize: 11, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ) + .animate() + .scale( + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + ) + .then(delay: const Duration(milliseconds: 300)); + } + + Widget _buildViewAnalyticsCard(BuildContext context) { + return Container( + height: 120, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE2E8F0), width: 1), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => context.go('/teacher/analytics'), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF6BA8A0).withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.analytics, + color: Color(0xFF6BA8A0), + size: 20, + ), + ), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Analytics', + style: TextStyle( + color: Color(0xFF2D3748), + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'Desempenho da turma', + style: TextStyle( + color: Color(0xFF718096), + fontSize: 11, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ) + .animate() + .scale( + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + ) + .then(delay: const Duration(milliseconds: 400)); + } +}