# Frontend MVP Tasks - AI Study Assistant ## ๐Ÿ“ฑ 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 teachit` - [ ] Configure Flutter SDK version (3.41.9 or latest stable) - [ ] Set up version control (Git repository) - [ ] Create initial project structure - [ ] Configure pubspec.yaml with initial dependencies #### Dependencies to Add: ```yaml dependencies: flutter: sdk: flutter # State Management flutter_riverpod: ^2.4.9 # Firebase firebase_core: ^2.24.2 firebase_auth: ^4.15.3 cloud_firestore: ^4.13.6 firebase_storage: ^11.5.6 # UI Components cupertino_icons: ^1.0.6 google_fonts: ^6.1.0 # Navigation go_router: ^12.1.3 # HTTP & Networking http: ^1.1.2 dio: ^5.4.0 # Local Storage shared_preferences: ^2.2.2 # Utilities intl: ^0.19.0 uuid: ^4.2.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.1 mockito: ^5.4.4 build_runner: ^2.4.7 ``` #### Implementation Details: ```bash # Create project flutter create teachit cd teachit # 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: - [ ] Implement Firebase Auth service - [ ] Create user models and entities - [ ] Build authentication repository - [ ] Implement sign in use case - [ ] Implement sign up use case - [ ] Implement password reset - [ ] Create authentication providers - [ ] Build login/signup screens #### 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*