# Frontend MVP Tasks - AI Study Assistant > ⚠️ **ATUALIZADO**: Este documento foi corrigido para refletir a implementação REAL. > > **Versão Flutter:** 3.11.5+ (não 3.41.9 como documentado anteriormente) > **Nota:** Não existe backend Node.js. Firebase BaaS é usado diretamente. ## 📱 MVP FRONTEND ROADMAP (8-12 WEEKS) --- ## 🎯 WEEK 1-2: FOUNDATION & SETUP ### Task 1.1: Flutter Project Initialization **Priority**: Critical **Estimated Time**: 4 hours **Dependencies**: None #### Subtasks: - [ ] Create new Flutter project: `flutter create learn_it` - [x] Configure Flutter SDK version (^3.11.5 or higher stable) - [ ] Set up version control (Git repository) - [ ] Create initial project structure - [ ] Configure pubspec.yaml with initial dependencies #### Actual Dependencies (from pubspec.yaml): ```yaml dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # State Management flutter_riverpod: ^2.4.9 riverpod_annotation: ^2.3.3 # Navigation go_router: ^12.1.3 flutter_animate: ^4.2.0+1 # Firebase firebase_core: ^2.25.4 firebase_auth: ^4.17.8 cloud_firestore: ^4.15.8 firebase_storage: ^11.6.9 firebase_analytics: ^10.8.0 firebase_messaging: ^14.9.3 firebase_crashlytics: ^3.5.7 # UI Components cupertino_icons: ^1.0.6 google_fonts: ^6.1.0 cached_network_image: ^3.3.0 flutter_svg: ^2.0.9 lottie: ^2.7.0 shimmer: ^3.0.0 # HTTP & Networking dio: ^5.4.0 http: ^1.1.2 connectivity_plus: ^5.0.2 # Local Storage shared_preferences: ^2.2.2 hive: ^2.2.3 hive_flutter: ^1.1.0 flutter_secure_storage: ^9.0.0 # PDF Processing (for RAG) syncfusion_flutter_pdf: ^33.2.6 file_selector: ^1.0.3 image_picker: ^1.0.4 # Utilities intl: ^0.20.2 uuid: ^4.2.1 equatable: ^2.0.5 # Charts fl_chart: ^0.64.0 # Biometrics local_auth: ^2.1.7 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.1 build_runner: ^2.4.7 mockito: ^5.4.4 ``` #### Implementation Details: ```bash # Create project flutter create learn_it cd learn_it # Initialize git git init git add . git commit -m "Initial Flutter project setup" # Add dependencies flutter pub add flutter_riverpod firebase_core firebase_auth cloud_firestore firebase_storage cupertino_icons google_fonts go_router http dio shared_preferences intl uuid flutter pub add --dev flutter_test flutter_lints mockito build_runner ``` --- ### Task 1.2: Project Structure Setup **Priority**: Critical **Estimated Time**: 6 hours **Dependencies**: Task 1.1 #### Folder Structure to Create: ``` lib/ ├── main.dart ├── app/ │ ├── app.dart │ ├── router/ │ │ ├── app_router.dart │ │ └── routes.dart │ └── theme/ │ ├── app_theme.dart │ ├── app_colors.dart │ ├── app_text_styles.dart │ └── app_spacing.dart ├── core/ │ ├── constants/ │ │ ├── app_constants.dart │ │ └── firebase_constants.dart │ ├── utils/ │ │ ├── logger.dart │ │ ├── validators.dart │ │ └── extensions.dart │ ├── errors/ │ │ ├── exceptions.dart │ │ └── failures.dart │ └── services/ │ ├── storage_service.dart │ └── notification_service.dart ├── features/ │ ├── auth/ │ │ ├── data/ │ │ │ ├── datasources/ │ │ │ │ ├── auth_remote_datasource.dart │ │ │ │ └── auth_local_datasource.dart │ │ │ ├── models/ │ │ │ │ ├── user_model.dart │ │ │ │ └── auth_result_model.dart │ │ │ └── repositories/ │ │ │ └── auth_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ ├── user.dart │ │ │ │ └── auth_result.dart │ │ │ ├── repositories/ │ │ │ │ └── auth_repository.dart │ │ │ └── usecases/ │ │ │ ├── sign_in.dart │ │ │ ├── sign_up.dart │ │ │ ├── sign_out.dart │ │ │ └── get_current_user.dart │ │ └── presentation/ │ │ ├── providers/ │ │ │ ├── auth_provider.dart │ │ │ └── user_provider.dart │ │ ├── screens/ │ │ │ ├── login_screen.dart │ │ │ ├── signup_screen.dart │ │ │ └── forgot_password_screen.dart │ │ └── widgets/ │ │ ├── auth_form.dart │ │ ├── social_login_button.dart │ │ └── password_input_field.dart │ ├── student/ │ │ ├── data/ │ │ │ ├── datasources/ │ │ │ │ ├── student_remote_datasource.dart │ │ │ │ └── student_local_datasource.dart │ │ │ ├── models/ │ │ │ │ ├── student_model.dart │ │ │ │ ├── learning_state_model.dart │ │ │ │ └── quiz_attempt_model.dart │ │ │ └── repositories/ │ │ │ └── student_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ ├── student.dart │ │ │ │ ├── learning_state.dart │ │ │ │ ├── concept_mastery.dart │ │ │ │ └── quiz_attempt.dart │ │ │ ├── repositories/ │ │ │ │ └── student_repository.dart │ │ │ └── usecases/ │ │ │ ├── get_learning_state.dart │ │ │ ├── update_learning_state.dart │ │ │ ├── submit_quiz_attempt.dart │ │ │ └── get_quiz_history.dart │ │ └── presentation/ │ │ ├── providers/ │ │ │ ├── student_provider.dart │ │ │ ├── learning_state_provider.dart │ │ │ └── quiz_provider.dart │ │ ├── screens/ │ │ │ ├── student_dashboard_screen.dart │ │ │ ├── ask_tutor_screen.dart │ │ │ ├── quiz_screen.dart │ │ │ ├── progress_screen.dart │ │ │ └── profile_screen.dart │ │ └── widgets/ │ │ ├── mastery_progress_bar.dart │ │ ├── concept_card.dart │ │ ├── quiz_question_card.dart │ │ ├── chat_bubble.dart │ │ └── feedback_widget.dart │ ├── teacher/ │ │ ├── data/ │ │ │ ├── datasources/ │ │ │ │ ├── teacher_remote_datasource.dart │ │ │ │ └── teacher_local_datasource.dart │ │ │ ├── models/ │ │ │ │ ├── teacher_model.dart │ │ │ │ ├── content_model.dart │ │ │ │ └── quiz_model.dart │ │ │ └── repositories/ │ │ │ └── teacher_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ ├── teacher.dart │ │ │ │ ├── content.dart │ │ │ │ └── quiz.dart │ │ │ ├── repositories/ │ │ │ │ └── teacher_repository.dart │ │ │ └── usecases/ │ │ │ ├── upload_content.dart │ │ │ ├── create_quiz.dart │ │ │ ├── get_class_analytics.dart │ │ │ └── manage_students.dart │ │ └── presentation/ │ │ ├── providers/ │ │ │ ├── teacher_provider.dart │ │ │ ├── content_provider.dart │ │ │ └── analytics_provider.dart │ │ ├── screens/ │ │ │ ├── teacher_dashboard_screen.dart │ │ │ ├── upload_content_screen.dart │ │ │ ├── create_quiz_screen.dart │ │ │ ├── class_analytics_screen.dart │ │ │ └── manage_students_screen.dart │ │ └── widgets/ │ │ ├── content_upload_card.dart │ │ ├── quiz_builder.dart │ │ ├── analytics_chart.dart │ │ └── student_list_item.dart │ └── shared/ │ ├── data/ │ │ ├── models/ │ │ │ ├── message_model.dart │ │ │ ├── feedback_model.dart │ │ │ └── notification_model.dart │ │ └── datasources/ │ │ ├── shared_remote_datasource.dart │ │ └── shared_local_datasource.dart │ ├── domain/ │ │ ├── entities/ │ │ │ ├── message.dart │ │ │ ├── feedback.dart │ │ │ └── notification.dart │ │ └── repositories/ │ │ └── shared_repository.dart │ └── presentation/ │ ├── widgets/ │ │ ├── custom_button.dart │ │ ├── custom_text_field.dart │ │ ├── loading_widget.dart │ │ ├── error_widget.dart │ │ ├── empty_state_widget.dart │ │ ├── confirmation_dialog.dart │ │ └── bottom_sheet.dart │ └── providers/ │ ├── theme_provider.dart │ ├── connectivity_provider.dart │ └── notification_provider.dart └── widgets/ ├── app_scaffold.dart ├── app_bottom_navigation.dart └── app_drawer.dart ``` --- ### Task 1.3: Theme & Design System Implementation **Priority**: Critical **Estimated Time**: 8 hours **Dependencies**: Task 1.2 #### Subtasks: - [ ] Implement AppColors class with EPVC color palette - [ ] Create AppTextStyles with typography system - [ ] Set up AppTheme with light/dark mode support - [ ] Implement custom widgets (buttons, cards, inputs) - [ ] Create animation utilities - [ ] Set up responsive design utilities #### Implementation Files: **lib/app/theme/app_colors.dart** ```dart import 'package:flutter/material.dart'; class AppColors { // Primary Brand Colors (from EPVC) static const Color primaryBlue = Color(0xFF4A90E2); static const Color primaryTeal = Color(0xFF5AC8FA); static const Color primaryOrange = Color(0xFFFF9500); // Gradient Colors static const Color gradientStart = Color(0xFF4A90E2); static const Color gradientEnd = Color(0xFF5AC8FA); // Neutral Colors static const Color background = Color(0xFFF8F9FA); static const Color surface = Color(0xFFFFFFFF); static const Color cardBackground = Color(0xFFFFFFFF); // Text Colors static const Color textPrimary = Color(0xFF1A1A1A); static const Color textSecondary = Color(0xFF6B7280); static const Color textHint = Color(0xFF9CA3AF); // Status Colors static const Color success = Color(0xFF10B981); static const Color warning = Color(0xFFF59E0B); static const Color error = Color(0xFFEF4444); static const Color info = Color(0xFF3B82F6); // Interactive Colors static const Color buttonPrimary = Color(0xFF4A90E2); static const Color buttonSecondary = Color(0xFFE5E7EB); static const Color iconActive = Color(0xFF4A90E2); static const Color iconInactive = Color(0xFF9CA3AF); // Chat Colors static const Color chatBubbleStudent = Color(0xFF4A90E2); static const Color chatBubbleAI = Color(0xFFF3F4F6); static const Color chatInputBackground = Color(0xFFF8F9FA); static const Color chatSendButton = Color(0xFF5AC8FA); } class AppDarkColors { static const Color background = Color(0xFF121212); static const Color surface = Color(0xFF1E1E1E); static const Color cardBackground = Color(0xFF2D2D2D); static const Color textPrimary = Color(0xFFFFFFFF); static const Color textSecondary = Color(0xFFB3B3B3); static const Color textHint = Color(0xFF808080); } ``` **lib/app/theme/app_theme.dart** ```dart import 'package:flutter/material.dart'; import 'app_colors.dart'; import 'app_text_styles.dart'; class AppTheme { static ThemeData get lightTheme { return ThemeData( useMaterial3: true, brightness: Brightness.light, colorScheme: const ColorScheme.light( primary: AppColors.primaryBlue, secondary: AppColors.primaryTeal, surface: AppColors.surface, background: AppColors.background, error: AppColors.error, onPrimary: Colors.white, onSecondary: Colors.white, onSurface: AppColors.textPrimary, onBackground: AppColors.textPrimary, onError: Colors.white, ), textTheme: const TextTheme( displayLarge: AppTextStyles.h1, displayMedium: AppTextStyles.h2, displaySmall: AppTextStyles.h3, bodyLarge: AppTextStyles.bodyLarge, bodyMedium: AppTextStyles.bodyMedium, bodySmall: AppTextStyles.bodySmall, labelLarge: AppTextStyles.buttonLarge, labelMedium: AppTextStyles.buttonMedium, labelSmall: AppTextStyles.caption, ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: AppColors.buttonPrimary, foregroundColor: Colors.white, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: AppColors.surface, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: AppColors.primaryBlue.withOpacity(0.3), width: 1, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: AppColors.primaryBlue.withOpacity(0.3), width: 1, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: AppColors.primaryBlue, width: 2, ), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: AppColors.error, width: 1, ), ), ), cardTheme: CardTheme( color: AppColors.cardBackground, elevation: 4, shadowColor: Colors.black.withOpacity(0.1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), ), ); } static ThemeData get darkTheme { return ThemeData( useMaterial3: true, brightness: Brightness.dark, colorScheme: const ColorScheme.dark( primary: AppColors.primaryBlue, secondary: AppColors.primaryTeal, surface: AppDarkColors.surface, background: AppDarkColors.background, error: AppColors.error, onPrimary: Colors.white, onSecondary: Colors.white, onSurface: AppDarkColors.textPrimary, onBackground: AppDarkColors.textPrimary, onError: Colors.white, ), // ... similar text theme and component themes for dark mode ); } } ``` --- ### Task 1.4: Firebase Configuration **Priority**: Critical **Estimated Time**: 4 hours **Dependencies**: Task 1.1 #### Subtasks: - [ ] Create Firebase project - [ ] Add Firebase configuration files - [ ] Initialize Firebase in app - [ ] Set up Firebase Auth configuration - [ ] Configure Firestore security rules - [ ] Set up Firebase Storage #### Implementation: **lib/core/constants/firebase_constants.dart** ```dart class FirebaseConstants { // Collections static const String usersCollection = 'users'; static const String schoolsCollection = 'schools'; static const String learningStatesCollection = 'learning_states'; static const String contentChunksCollection = 'content_chunks'; static const String quizzesCollection = 'quizzes'; static const String quizAttemptsCollection = 'quiz_attempts'; static const String interactionsCollection = 'interactions'; static const String auditLogsCollection = 'audit_logs'; // Storage paths static const String contentStoragePath = 'content/'; static const String profileImagesPath = 'profile_images/'; static const String tempFilesPath = 'temp/'; // User roles static const String studentRole = 'student'; static const String teacherRole = 'teacher'; static const String adminRole = 'admin'; // Default values static const int defaultQuizDuration = 30; // minutes static const int maxChunkSize = 400; // tokens static const int maxRetrievalChunks = 5; } ``` --- ## 🔐 WEEK 3-4: AUTHENTICATION & USER MANAGEMENT ### Task 2.1: Authentication System **Priority**: Critical **Estimated Time**: 12 hours **Dependencies**: Task 1.4 #### Subtasks: - [x] Implement Firebase Auth service - [x] Create user models and entities - [x] Build authentication repository - [x] Implement sign in use case - [x] Implement sign up use case - [ ] Implement password reset - [x] Create authentication providers - [x] Build login/signup screens (with navigation improvements and theme fixes) **Recent Updates:** - ✅ Enhanced authentication navigation with PopScope for Android back button support - ✅ Removed AppBar and added custom positioned back button with aesthetic design - ✅ Fixed theme consistency in signup page input fields (light/dark mode) - ✅ Navigation flow complete: back button navigates to role-selection #### Implementation: **lib/features/auth/data/datasources/auth_remote_datasource.dart** ```dart import 'package:firebase_auth/firebase_auth.dart'; import '../models/user_model.dart'; abstract class AuthRemoteDataSource { Future signInWithEmail(String email, String password); Future signUpWithEmail(String email, String password, String name, String role); Future signInWithGoogle(); Future sendPasswordResetEmail(String email); Future signOut(); Future getCurrentUser(); Stream authStateChanges(); } class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { final FirebaseAuth _firebaseAuth; AuthRemoteDataSourceImpl(this._firebaseAuth); @override Future signInWithEmail(String email, String password) async { try { final result = await _firebaseAuth.signInWithEmailAndPassword( email: email, password: password, ); return UserModel.fromFirebaseUser(result.user!); } catch (e) { throw AuthException(e.toString()); } } @override Future signUpWithEmail( String email, String password, String name, String role ) async { try { final result = await _firebaseAuth.createUserWithEmailAndPassword( email: email, password: password, ); // Update user profile await result.user!.updateDisplayName(name); return UserModel.fromFirebaseUser( result.user!, role: role, displayName: name, ); } catch (e) { throw AuthException(e.toString()); } } @override Future signInWithGoogle() async { // Implement Google Sign-In throw UnimplementedError(); } @override Future sendPasswordResetEmail(String email) async { try { await _firebaseAuth.sendPasswordResetEmail(email: email); } catch (e) { throw AuthException(e.toString()); } } @override Future signOut() async { await _firebaseAuth.signOut(); } @override Future getCurrentUser() async { final user = _firebaseAuth.currentUser; return user != null ? UserModel.fromFirebaseUser(user) : null; } @override Stream authStateChanges() { return _firebaseAuth.authStateChanges().map((user) { return user != null ? UserModel.fromFirebaseUser(user) : null; }); } } ``` **lib/features/auth/presentation/screens/login_screen.dart** ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/auth_provider.dart'; import '../../../shared/widgets/custom_button.dart'; import '../../../shared/widgets/custom_text_field.dart'; class LoginScreen extends ConsumerStatefulWidget { const LoginScreen({Key? key}) : super(key: key); @override ConsumerState createState() => _LoginScreenState(); } class _LoginScreenState extends ConsumerState { final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _formKey = GlobalKey(); bool _obscurePassword = true; bool _isLoading = false; @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } Future _handleLogin() async { if (!_formKey.currentState!.validate()) return; setState(() => _isLoading = true); try { await ref.read(authProvider.notifier).signIn( email: _emailController.text.trim(), password: _passwordController.text, ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Login failed: ${e.toString()}'), backgroundColor: Theme.of(context).colorScheme.error, ), ); } finally { setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ AppColors.gradientStart, AppColors.gradientEnd, ], ), ), child: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 60), // Logo and Title Column( children: [ Container( width: 80, height: 80, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: const Icon( Icons.school, size: 40, color: AppColors.primaryBlue, ), ), const SizedBox(height: 16), const Text( 'AI Study Assistant', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 8), const Text( 'Escola Profissional de Vila do Conde', style: TextStyle( fontSize: 16, color: Colors.white70, ), ), ], ), const SizedBox(height: 60), // Login Form Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'Welcome Back', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), CustomTextField( controller: _emailController, label: 'Email', hint: 'Enter your email', keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return 'Please enter a valid email'; } return null; }, ), const SizedBox(height: 16), CustomTextField( controller: _passwordController, label: 'Password', hint: 'Enter your password', obscureText: _obscurePassword, suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() => _obscurePassword = !_obscurePassword); }, ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } if (value.length < 6) { return 'Password must be at least 6 characters'; } return null; }, ), const SizedBox(height: 24), CustomButton( text: 'Sign In', onPressed: _handleLogin, isLoading: _isLoading, ), const SizedBox(height: 16), TextButton( onPressed: () { // Navigate to forgot password }, child: const Text( 'Forgot Password?', style: TextStyle( color: AppColors.primaryBlue, fontWeight: FontWeight.w500, ), ), ), ], ), ), const SizedBox(height: 32), // Sign Up Link Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( "Don't have an account? ", style: TextStyle(color: Colors.white), ), TextButton( onPressed: () { // Navigate to sign up }, child: const Text( 'Sign Up', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ], ), ], ), ), ), ), ), ); } } ``` --- ### Task 2.2: User Role Management **Priority**: High **Estimated Time**: 8 hours **Dependencies**: Task 2.1 #### Subtasks: - [ ] Implement role-based routing - [ ] Create user profile screens - [ ] Build role-specific navigation - [ ] Implement user settings - [ ] Create user management (for teachers/admins) --- ## 📚 WEEK 5-6: STUDENT FEATURES ### Task 3.1: Student Dashboard **Priority**: High **Estimated Time**: 16 hours **Dependencies**: Task 2.2 #### Subtasks: - [ ] Design dashboard layout - [ ] Implement mastery progress cards - [ ] Create concept review widgets - [ ] Build misconception indicators - [ ] Add learning streak tracker - [ ] Implement quick action buttons #### Implementation: **lib/features/student/presentation/screens/student_dashboard_screen.dart** ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/learning_state_provider.dart'; import '../../../shared/widgets/mastery_progress_bar.dart'; import '../../../shared/widgets/concept_card.dart'; import '../../../shared/widgets/custom_button.dart'; class StudentDashboardScreen extends ConsumerStatefulWidget { const StudentDashboardScreen({Key? key}) : super(key: key); @override ConsumerState createState() => _StudentDashboardScreenState(); } class _StudentDashboardScreenState extends ConsumerState with TickerProviderStateMixin { late AnimationController _fadeController; late AnimationController _slideController; @override void initState() { super.initState(); _fadeController = AnimationController( duration: const Duration(milliseconds: 600), vsync: this, ); _slideController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _fadeController.forward(); _slideController.forward(); } @override void dispose() { _fadeController.dispose(); _slideController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final learningState = ref.watch(learningStateProvider); final recommendations = ref.watch(recommendationsProvider); return Scaffold( appBar: AppBar( title: const Text('My Learning'), backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, elevation: 0, ), body: RefreshIndicator( onRefresh: () async { await ref.refresh(learningStateProvider.future); }, child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Welcome Section FadeTransition( opacity: _fadeController, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Welcome back, ${learningState.value?.profile.name ?? 'Student'}!', style: AppTextStyles.h2, ), const SizedBox(height: 8), Text( 'Continue your learning journey', style: AppTextStyles.bodyMedium.copyWith( color: AppColors.textSecondary, ), ), ], ), ), const SizedBox(height: 24), // Summary Cards SlideTransition( position: Tween( begin: const Offset(0, 0.3), end: Offset.zero, ).animate(CurvedAnimation( parent: _slideController, curve: Curves.easeOut, )), child: Row( children: [ Expanded( child: _buildSummaryCard( title: 'Average Mastery', value: '${(learningState.value?.averageMastery * 100 ?? 0).toInt()}%', icon: Icons.trending_up, color: AppColors.success, ), ), const SizedBox(width: 12), Expanded( child: _buildSummaryCard( title: 'Learning Streak', value: '${learningState.value?.learningStreak ?? 0} days', icon: Icons.local_fire_department, color: AppColors.primaryOrange, ), ), ], ), ), const SizedBox(height: 24), // Concepts to Review _buildSectionTitle('Concepts to Review'), const SizedBox(height: 12), SizedBox( height: 120, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: learningState.value?.spacedRepetition.length ?? 0, itemBuilder: (context, index) { final concept = learningState.value!.spacedRepetition[index]; return Container( width: 200, margin: const EdgeInsets.only(right: 12), child: ConceptCard( conceptId: concept.conceptId, dueDate: concept.dueDate, priority: concept.priority, onTap: () { // Navigate to concept details }, ), ); }, ), ), const SizedBox(height: 24), // Misconceptions if (learningState.value?.misconceptions.isNotEmpty == true) ...[ _buildSectionTitle('Address Misconceptions'), const SizedBox(height: 12), ...learningState.value!.misconceptions.map( (misconception) => Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.warning.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: AppColors.warning.withOpacity(0.3), ), ), child: Row( children: [ Icon( Icons.warning, color: AppColors.warning, size: 20, ), const SizedBox(width: 12), Expanded( child: Text( misconception.description, style: AppTextStyles.bodyMedium, ), ), CustomButton( text: 'Fix', onPressed: () { // Navigate to remedial content }, isSmall: true, ), ], ), ), ), const SizedBox(height: 24), ], // Recommended Actions _buildSectionTitle('Recommended for You'), const SizedBox(height: 12), ...recommendations.when( data: (actions) => actions.map( (action) => Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.cardBackground, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Row( children: [ Icon( _getActionIcon(action.type), color: AppColors.primaryBlue, size: 24, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( action.description, style: AppTextStyles.bodyMedium, ), if (action.estimatedTime != null) ...[ const SizedBox(height: 4), Text( 'Est. ${action.estimatedTime} min', style: AppTextStyles.caption, ), ], ], ), ), CustomButton( text: 'Start', onPressed: () => _handleAction(action), isSmall: true, ), ], ), ), ), loading: () => const Center( child: CircularProgressIndicator(), ), error: (error, stack) => Center( child: Text('Error: $error'), ), ), const SizedBox(height: 24), // Quick Actions _buildSectionTitle('Quick Actions'), const SizedBox(height: 12), Row( children: [ Expanded( child: CustomButton( text: 'Ask Tutor', onPressed: () { // Navigate to chat }, icon: Icons.chat, ), ), const SizedBox(width: 12), Expanded( child: CustomButton( text: 'Take Quiz', onPressed: () { // Navigate to quiz }, icon: Icons.quiz, isSecondary: true, ), ), ], ), ], ), ), ), ); } Widget _buildSummaryCard({ required String title, required String value, required IconData icon, required Color color, }) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: color.withOpacity(0.3), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, color: color, size: 24), const SizedBox(height: 8), Text( title, style: AppTextStyles.caption.copyWith( color: color, ), ), const SizedBox(height: 4), Text( value, style: AppTextStyles.h3.copyWith( color: color, fontWeight: FontWeight.bold, ), ), ], ), ); } Widget _buildSectionTitle(String title) { return Text( title, style: AppTextStyles.h3, ); } IconData _getActionIcon(String actionType) { switch (actionType) { case 'remedial': return Icons.healing; case 'review': return Icons.refresh; case 'new_learning': return Icons.add_circle; case 'exploration': return Icons.explore; default: return Icons.lightbulb; } } void _handleAction(RecommendedAction action) { switch (action.type) { case 'remedial': // Navigate to remedial content break; case 'review': // Navigate to review screen break; case 'new_learning': // Navigate to new concept break; case 'exploration': // Navigate to exploration break; } } } ``` --- ### Task 3.2: AI Tutor Chat Interface **Priority**: High **Estimated Time**: 20 hours **Dependencies**: Task 3.1 #### Subtasks: - [ ] Design chat interface layout - [ ] Implement message bubbles (student/AI) - [ ] Create chat input with send button - [ ] Add typing indicators - [ ] Implement message history - [ ] Add feedback collection - [ ] Create smooth animations #### Implementation: **lib/features/student/presentation/screens/ask_tutor_screen.dart** ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/chat_provider.dart'; import '../../../shared/widgets/chat_bubble.dart'; import '../../../shared/widgets/custom_text_field.dart'; class AskTutorScreen extends ConsumerStatefulWidget { const AskTutorScreen({Key? key}) : super(key: key); @override ConsumerState createState() => _AskTutorScreenState(); } class _AskTutorScreenState extends ConsumerState { final _messageController = TextEditingController(); final _scrollController = ScrollController(); final _focusNode = FocusNode(); @override void dispose() { _messageController.dispose(); _scrollController.dispose(); _focusNode.dispose(); super.dispose(); } void _scrollToBottom() { WidgetsBinding.instance.addPostFrameCallback((_) { if (_scrollController.hasClients) { _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); } }); } Future _sendMessage() async { final message = _messageController.text.trim(); if (message.isEmpty) return; _messageController.clear(); _focusNode.unfocus(); try { await ref.read(chatProvider.notifier).sendMessage(message); _scrollToBottom(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Failed to send message: $e'), backgroundColor: Theme.of(context).colorScheme.error, ), ); } } @override Widget build(BuildContext context) { final messages = ref.watch(chatProvider); return Scaffold( appBar: AppBar( title: const Text('AI Tutor'), backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, elevation: 0, ), body: Column( children: [ // Messages List Expanded( child: messages.when( data: (messageList) => ListView.builder( controller: _scrollController, padding: const EdgeInsets.all(16), itemCount: messageList.length, itemBuilder: (context, index) { final message = messageList[index]; return ChatBubble( message: message, showAvatar: message.role == 'assistant', onFeedback: (feedback) { ref.read(chatProvider.notifier).submitFeedback( messageId: message.id, feedback: feedback, ); }, ); }, ), loading: () => const Center( child: CircularProgressIndicator(), ), error: (error, stack) => Center( child: Text('Error: $error'), ), ), ), // Typing Indicator Consumer( builder: (context, ref, child) { final isTyping = ref.watch(isTypingProvider); return isTyping ? Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: AppColors.chatBubbleAI, borderRadius: BorderRadius.circular(16), ), child: Row( children: [ SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(AppColors.textSecondary), ), ), const SizedBox(width: 8), Text( 'AI is thinking...', style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), ), ], ), ), ], ), ) : const SizedBox.shrink(); }, ), // Input Area Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.chatInputBackground, border: Border( top: BorderSide( color: AppColors.primaryBlue.withOpacity(0.1), ), ), ), child: Row( children: [ Expanded( child: CustomTextField( controller: _messageController, hint: 'Ask a question...', maxLines: 3, minLines: 1, focusNode: _focusNode, onSubmitted: (_) => _sendMessage(), ), ), const SizedBox(width: 12), Container( width: 48, height: 48, decoration: BoxDecoration( color: AppColors.chatSendButton, borderRadius: BorderRadius.circular(24), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(24), onTap: _sendMessage, child: const Icon( Icons.send, color: Colors.white, size: 24, ), ), ), ), ], ), ), ], ), ); } } ``` --- ### Task 3.3: Quiz System **Priority**: High **Estimated Time**: 16 hours **Dependencies**: Task 3.1 #### Subtasks: - [ ] Create quiz question cards - [ ] Implement multiple choice interface - [ ] Add timer functionality - [ ] Build progress tracking - [ ] Create quiz results screen - [ ] Implement quiz history --- ## 👨‍🏫 WEEK 7-8: TEACHER FEATURES ### Task 4.1: Teacher Dashboard **Priority**: High **Estimated Time**: 12 hours **Dependencies**: Task 2.2 #### Subtasks: - [ ] Design teacher dashboard layout - [ ] Create class overview cards - [ ] Implement analytics widgets - [ ] Add quick action buttons - [ ] Build student performance summary --- ### Task 4.2: Content Upload System **Priority**: High **Estimated Time**: 16 hours **Dependencies**: Task 4.1 #### Subtasks: - [ ] Create file upload interface - [ ] Implement PDF parsing preview - [ ] Add content chunking preview - [ ] Build metadata editing - [ ] Create content management list --- ### Task 4.3: Quiz Creation **Priority**: Medium **Estimated Time**: 12 hours **Dependencies**: Task 4.1 #### Subtasks: - [ ] Build quiz builder interface - [ ] Add question type selection - [ ] Implement question editor - [ ] Create quiz settings - [ ] Add preview functionality --- ## 🧪 WEEK 9-10: TESTING & POLISH ### Task 5.1: Unit Tests **Priority**: High **Estimated Time**: 16 hours **Dependencies**: All previous tasks #### Subtasks: - [ ] Write tests for all use cases - [ ] Test repository implementations - [ ] Test provider logic - [ ] Test widget rendering - [ ] Test user interactions --- ### Task 5.2: Integration Tests **Priority**: High **Estimated Time**: 12 hours **Dependencies**: Task 5.1 #### Subtasks: - [ ] Test authentication flow - [ ] Test complete user journeys - [ ] Test Firebase integration - [ ] Test API communication - [ ] Test error handling --- ### Task 5.3: UI Polish **Priority**: Medium **Estimated Time**: 8 hours **Dependencies**: Task 5.2 #### Subtasks: - [ ] Refine animations - [ ] Improve responsive design - [ ] Add micro-interactions - [ ] Optimize performance - [ ] Fix UI inconsistencies --- ## 📱 WEEK 11-12: FINALIZATION ### Task 6.1: Performance Optimization **Priority**: High **Estimated Time**: 8 hours **Dependencies**: Task 5.3 #### Subtasks: - [ ] Profile app performance - [ ] Optimize image loading - [ ] Reduce bundle size - [ ] Implement lazy loading - [ ] Optimize Firebase queries --- ### Task 6.2: Documentation **Priority**: Medium **Estimated Time**: 8 hours **Dependencies**: Task 6.1 #### Subtasks: - [ ] Document API endpoints - [ ] Create user guide - [ ] Write deployment instructions - [ ] Document architecture - [ ] Create troubleshooting guide --- ## 🚀 DELIVERABLES ### Week 2 Deliverables - [ ] Flutter project with complete structure - [ ] Design system implementation - [ ] Firebase configuration - [ ] Basic authentication flow ### Week 4 Deliverables - [ ] Complete authentication system - [ ] User role management - [ ] User profiles - [ ] Navigation system ### Week 6 Deliverables - [ ] Student dashboard - [ ] AI tutor chat interface - [ ] Quiz system - [ ] Progress tracking ### Week 8 Deliverables - [ ] Teacher dashboard - [ ] Content upload system - [ ] Quiz creation tools - [ ] Basic analytics ### Week 10 Deliverables - [ ] Complete test suite - [ ] Polished UI - [ ] Error handling - [ ] Performance optimizations ### Week 12 Deliverables - [ ] Production-ready app - [ ] Complete documentation - [ ] Deployment ready - [ ] User testing feedback incorporated --- ## 📋 QUALITY CHECKLIST ### Code Quality - [ ] All code follows Flutter/Dart conventions - [ ] Proper error handling throughout - [ ] No hardcoded values (use constants) - [ ] Proper state management implementation - [ ] Clean architecture maintained ### UI/UX Quality - [ ] Design system consistently applied - [ ] Responsive design works on all screen sizes - [ ] Animations are smooth and purposeful - [ ] Accessibility features implemented - [ ] Dark mode support ### Performance - [ ] App launches within 3 seconds - [ ] Smooth 60 FPS animations - [ ] Memory usage optimized - [ ] Network requests efficient - [ ] No memory leaks ### Testing - [ ] Unit test coverage > 80% - [ ] All critical paths tested - [ ] Firebase integration tested - [ ] Error scenarios tested - [ ] Performance benchmarks met --- *Last Updated: 2026-05-06* *Version: 1.0.0* *Frontend Lead: Flutter Development Team*