Files
LearnIT/docs/FRONTEND_MVP_TASKS.md

52 KiB

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:

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:

# 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

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

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

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

import 'package:firebase_auth/firebase_auth.dart';
import '../models/user_model.dart';

abstract class AuthRemoteDataSource {
  Future<UserModel> signInWithEmail(String email, String password);
  Future<UserModel> signUpWithEmail(String email, String password, String name, String role);
  Future<UserModel> signInWithGoogle();
  Future<void> sendPasswordResetEmail(String email);
  Future<void> signOut();
  Future<UserModel?> getCurrentUser();
  Stream<UserModel?> authStateChanges();
}

class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final FirebaseAuth _firebaseAuth;
  
  AuthRemoteDataSourceImpl(this._firebaseAuth);
  
  @override
  Future<UserModel> 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<UserModel> 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<UserModel> signInWithGoogle() async {
    // Implement Google Sign-In
    throw UnimplementedError();
  }
  
  @override
  Future<void> sendPasswordResetEmail(String email) async {
    try {
      await _firebaseAuth.sendPasswordResetEmail(email: email);
    } catch (e) {
      throw AuthException(e.toString());
    }
  }
  
  @override
  Future<void> signOut() async {
    await _firebaseAuth.signOut();
  }
  
  @override
  Future<UserModel?> getCurrentUser() async {
    final user = _firebaseAuth.currentUser;
    return user != null ? UserModel.fromFirebaseUser(user) : null;
  }
  
  @override
  Stream<UserModel?> authStateChanges() {
    return _firebaseAuth.authStateChanges().map((user) {
      return user != null ? UserModel.fromFirebaseUser(user) : null;
    });
  }
}

lib/features/auth/presentation/screens/login_screen.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<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends ConsumerState<LoginScreen> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool _obscurePassword = true;
  bool _isLoading = false;

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  Future<void> _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

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<StudentDashboardScreen> createState() => _StudentDashboardScreenState();
}

class _StudentDashboardScreenState extends ConsumerState<StudentDashboardScreen> 
    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<Offset>(
                  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

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<AskTutorScreen> createState() => _AskTutorScreenState();
}

class _AskTutorScreenState extends ConsumerState<AskTutorScreen> {
  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<void> _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