diff --git a/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_classroom_api.dart b/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_classroom_api.dart index eb50e7a6..f067f878 100644 --- a/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_classroom_api.dart +++ b/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_classroom_api.dart @@ -201,7 +201,7 @@ class GoogleClassroomApi { int day = int.parse(dateParts[2]); int hours = int.parse(dateParts[3]); int minutes = int.parse(dateParts[4]); - String? topicId = await getTopicId(courseId, 'Quiz') ?? '755868506953'; + String? topicId = await getTopicId(courseId, 'quiz') ?? '755868506953'; print('topic id is : $topicId'); diff --git a/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_lms_service.dart b/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_lms_service.dart index 6d49afe9..03e0b079 100644 --- a/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_lms_service.dart +++ b/LearningLens2025/frontend/lib/Api/lms/google_classroom/google_lms_service.dart @@ -1,17 +1,21 @@ import 'dart:convert'; import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:http/http.dart' as http; import 'package:learninglens_app/Api/lms/google_classroom/google_classroom_api.dart'; // Import the updated API import 'package:learninglens_app/Api/lms/lms_interface.dart'; +import 'package:learninglens_app/Views/assessments_view.dart'; import 'package:learninglens_app/beans/assignment.dart'; import 'package:learninglens_app/beans/course.dart'; import 'package:learninglens_app/beans/g_question_form_data.dart'; import 'package:learninglens_app/beans/grade.dart'; import 'package:learninglens_app/beans/moodle_rubric.dart'; +import 'package:learninglens_app/beans/override.dart'; import 'package:learninglens_app/beans/participant.dart'; import 'package:learninglens_app/beans/quiz.dart'; +import 'package:learninglens_app/beans/quiz_override'; import 'package:learninglens_app/beans/quiz_type.dart'; import 'package:learninglens_app/beans/submission.dart'; import 'package:learninglens_app/beans/submission_status.dart'; @@ -65,6 +69,8 @@ class GoogleLmsService extends LmsInterface { String? profileImage; @override List? courses; + @override + List? overrides; late GoogleSignIn _googleSignIn; @@ -310,11 +316,11 @@ class GoogleLmsService extends LmsInterface { // Iterate and capture topicIds for (var topic in topics) { - if (topic['name'] == 'Quiz') { + if (topic['name'] == 'quiz') { course.quizTopicId = int.parse(topic['topicId']); // print('Id for quiz'); // print(topic['topicId']); - } else if (topic['name'] == 'Essay') { + } else if (topic['name'] == 'essay') { course.essayTopicId = int.parse(topic['topicId']); // print('Id for essay'); // print(topic['topicId']); @@ -350,8 +356,9 @@ class GoogleLmsService extends LmsInterface { if (studentsJson.containsKey('students')) { for (var student in studentsJson['students']) { participants.add(Participant( - id: student['userId'] - .hashCode, // Google Classroom does not provide numeric IDs + // TODO: Int will parse incorrectly. Will need to swap to String or BigInt + // e.g. 123456789012345 would parse to something like 123456789010000 + id: int.parse(student['profile']['id']), fullname: student['profile']['name']['fullName'], firstname: student['profile']['name']['givenName'], lastname: student['profile']['name']['familyName'], @@ -433,6 +440,8 @@ class GoogleLmsService extends LmsInterface { headers: {'Authorization': 'Bearer $_userToken'}, ); + topicId ??= courses?.firstWhere((c) => c.id == courseID).quizTopicId; + // print('quizlist: ${response.body}'); if (response.statusCode != 200) { @@ -469,7 +478,8 @@ class GoogleLmsService extends LmsInterface { @override Future createQuiz(String courseid, String quizname, String quizintro, - String sectionid, String timeopen, String timeclose) async { + String sectionid, String timeopen, String timeclose, + {List individualStudentsOptions = const []}) async { print('Creating quiz in Google Classroom...'); print('Course ID: $courseid'); print('Quiz Name: $quizname'); @@ -482,8 +492,8 @@ class GoogleLmsService extends LmsInterface { // Convert timeopen to ISO 8601 format String formattedTimeOpen = DateTime.parse(timeopen).toIso8601String(); - String? assignmentId = await createAssignmentHelper( - courseid, quizname, quizintro, sectionid, formattedTimeOpen); + String? assignmentId = await createAssignmentHelper(courseid, quizname, + quizintro, sectionid, formattedTimeOpen, individualStudentsOptions); if (assignmentId != null) { return int.parse(assignmentId); @@ -497,8 +507,13 @@ class GoogleLmsService extends LmsInterface { } } - Future createAssignmentHelper(String courseId, String title, - String description, String responderUri, String dueDate) async { + Future createAssignmentHelper( + String courseId, + String title, + String description, + String responderUri, + String dueDate, + List individualStudentsOptions) async { print('Creating assignment in Google Classroom... Inside helper'); print('Course ID: $courseId'); print('Title: $title'); @@ -522,7 +537,7 @@ class GoogleLmsService extends LmsInterface { // Parse the dueDate string DateTime parsedDate = DateTime.parse(dueDate); - final body = jsonEncode({ + var requestBody = { "title": title, "description": description, "workType": "ASSIGNMENT", @@ -542,7 +557,15 @@ class GoogleLmsService extends LmsInterface { "link": {"url": responderUri} } ] - }); + }; + + if (individualStudentsOptions.isNotEmpty) { + requestBody['individualStudentsOptions'] = { + "studentIds": individualStudentsOptions + }; + } + + final body = jsonEncode(requestBody); // Print request details print('Request URL: $url'); @@ -808,6 +831,8 @@ class GoogleLmsService extends LmsInterface { throw StateError('User not logged in to Google Classroom'); } + topicId ??= courses?.firstWhere((c) => c.id == courseID).essayTopicId; + final response = await ApiService().httpGet( Uri.parse( 'https://classroom.googleapis.com/v1/courses/$courseID/courseWork'), @@ -874,14 +899,14 @@ class GoogleLmsService extends LmsInterface { @override // TODO - google API doesn't have an endpoint to pass in the rubric like Moodle Future?> createAssignment( - String courseid, - String sectionid, - String assignmentName, - String startdate, - String enddate, - String rubricJson, - String description, - ) async { + String courseid, + String sectionid, + String assignmentName, + String startdate, + String enddate, + String rubricJson, + String description, + {List individualStudentsOptions = const []}) async { print('Creating assignment...'); print('Course ID: $courseid'); print('Section ID: $sectionid'); @@ -915,6 +940,13 @@ class GoogleLmsService extends LmsInterface { }; } + if (individualStudentsOptions.isNotEmpty) { + body['assigneeMode'] = 'INDIVIDUAL_STUDENTS'; + body['individualStudentsOptions'] = { + "studentIds": individualStudentsOptions, + }; + } + if (availabilityDate != null) { body['scheduledTime'] = availabilityDate.toUtc().toIso8601String(); } @@ -1374,8 +1406,131 @@ class GoogleLmsService extends LmsInterface { } @override - Future>> getSubmissionAttachments( - {required int assignId}) { - throw UnimplementedError(); + Future refreshOverrides() async { + List override = []; + if (courses != null) { + for (Course c in courses!) { + List parts = await getCourseParticipants(c.id.toString()); + for (Participant p in parts) { + print(p.id); + } + var quizzes = (await getQuizzes(c.id, topicId: c.quizTopicId)) + .where((q) => q.individualStudentsOptions.isNotEmpty); + for (Quiz q in quizzes) { + for (int p in q.individualStudentsOptions) { + override.add(Override( + override.length, + "quiz", + q.id!, + q.name!, + c.id, + c.fullName, + p, + parts.firstWhere((part) => part.id == p).fullname, + q.timeClose, + null, + q.timeClose, + 0)); + } + } + var essays = (await getEssays(c.id, topicId: c.essayTopicId)) + .where((e) => e.individualStudentsOptions.isNotEmpty); + for (Assignment e in essays) { + for (int p in e.individualStudentsOptions) { + override.add(Override( + override.length, + "essay", + e.id, + e.name, + c.id, + c.fullName, + p, + parts.firstWhere((part) => part.id == p).fullname, + e.dueDate, + null, + e.cutoffDate, + 0)); + } + } + } + } + } + + @override + Future addEssayOverride( + {required int assignid, + int? courseId, + int? userId, + int? groupId, + int? allowsubmissionsfromdate, + int? dueDate, + int? cutoffDate, + int? timelimit, + int? sortorder}) async { + if (courseId == null) { + return ""; + } + var assignment = + getCourse(courseId).essays?.firstWhereOrNull((e) => e.id == assignid); + if (assignment == null) { + print(getCourse(courseId).essays); + return ""; + } + print("due date: $dueDate"); + var response = await createAssignment( + courseId.toString(), + "", + assignment.name, + (assignment.allowsubmissionsfromdate?.millisecondsSinceEpoch ?? + DateTime.now().millisecondsSinceEpoch) + .toString(), + (dueDate == null + ? assignment.dueDate?.millisecondsSinceEpoch ?? + DateTime.now().millisecondsSinceEpoch + : dueDate * 1000) + .toString(), + assignment.maxScore.toString(), + assignment.description, + individualStudentsOptions: [userId!]); + print(response); + return "Created essay override"; + } + + @override + Future addQuizOverride( + {required int quizId, + int? courseId, + int? userId, + int? groupId, + int? timeOpen, + int? timeClose, + int? timeLimit, + int? attempts, + String? password}) async { + if (courseId == null) { + return QuizOverride.empty(); + } + var assignment = + getCourse(courseId).quizzes?.firstWhereOrNull((e) => e.id == quizId); + if (assignment == null) { + return QuizOverride.empty(); + } + + await createQuiz( + courseId.toString(), + assignment.name!, + assignment.description ?? "", + "", + (timeOpen == null + ? assignment.timeOpen + : DateTime.fromMillisecondsSinceEpoch(timeOpen)) + .toString(), + (timeClose == null + ? assignment.timeClose?.millisecondsSinceEpoch ?? + DateTime.now().millisecondsSinceEpoch + : timeClose * 1000) + .toString(), + individualStudentsOptions: [userId!]); + return QuizOverride.empty(); } } diff --git a/LearningLens2025/frontend/lib/Api/lms/lms_interface.dart b/LearningLens2025/frontend/lib/Api/lms/lms_interface.dart index 8aea4e66..a0137000 100644 --- a/LearningLens2025/frontend/lib/Api/lms/lms_interface.dart +++ b/LearningLens2025/frontend/lib/Api/lms/lms_interface.dart @@ -4,8 +4,10 @@ import 'package:learninglens_app/beans/assignment.dart'; import 'package:learninglens_app/beans/course.dart'; import 'package:learninglens_app/beans/grade.dart'; import 'package:learninglens_app/beans/moodle_rubric.dart'; +import 'package:learninglens_app/beans/override.dart'; import 'package:learninglens_app/beans/participant.dart'; import 'package:learninglens_app/beans/quiz.dart'; +import 'package:learninglens_app/beans/quiz_override'; import 'package:learninglens_app/beans/quiz_type.dart'; import 'package:learninglens_app/beans/submission.dart'; import 'package:learninglens_app/beans/submission_status.dart'; @@ -27,6 +29,7 @@ abstract class LmsInterface { String? profileImage; List? courses; UserRole? role; + List? overrides; // Authentication/Login methods Future login(String username, String password, String baseURL); @@ -104,6 +107,8 @@ abstract class LmsInterface { required int draftItemId, }); + Future refreshOverrides(); + Future submitAssignmentForGrading({ required int assignId, bool acceptSubmissionStatement, @@ -119,4 +124,26 @@ abstract class LmsInterface { {required int assignId}) { throw UnimplementedError(); } + + Future addQuizOverride( + {required int quizId, + int? userId, + int? groupId, + int? timeOpen, + int? timeClose, + int? timeLimit, + int? attempts, + String? password, + int? courseId}); + + Future addEssayOverride( + {required int assignid, + int? userId, + int? groupId, + int? allowsubmissionsfromdate, + int? dueDate, + int? cutoffDate, + int? timelimit, + int? sortorder, + int? courseId}); } diff --git a/LearningLens2025/frontend/lib/Api/lms/moodle/moodle_lms_service.dart b/LearningLens2025/frontend/lib/Api/lms/moodle/moodle_lms_service.dart index 85df6281..e86a8465 100644 --- a/LearningLens2025/frontend/lib/Api/lms/moodle/moodle_lms_service.dart +++ b/LearningLens2025/frontend/lib/Api/lms/moodle/moodle_lms_service.dart @@ -63,10 +63,11 @@ class MoodleLmsService implements LmsInterface { @override UserRole? role; - List? overrides; - int? userId; + @override + List? overrides; + String? get userToken => _userToken; // **************************************************************************************** @@ -139,6 +140,7 @@ class MoodleLmsService implements LmsInterface { return _userToken != null; } + @override Future refreshOverrides() async { List>> futures = [ _getQuizOverrides(), @@ -1017,16 +1019,17 @@ class MoodleLmsService implements LmsInterface { } } - Future addQuizOverride({ - required int quizId, - int? userId, - int? groupId, - int? timeOpen, - int? timeClose, - int? timeLimit, - int? attempts, - String? password, - }) async { + @override + Future addQuizOverride( + {required int quizId, + int? userId, + int? groupId, + int? timeOpen, + int? timeClose, + int? timeLimit, + int? attempts, + String? password, + int? courseId}) async { if (_userToken == null) throw StateError('User not logged in to Moodle'); final url = Uri.parse('$apiURL$serverUrl'); @@ -1059,16 +1062,17 @@ class MoodleLmsService implements LmsInterface { } } - Future addEssayOverride({ - required int assignid, - int? userId, - int? groupId, - int? allowsubmissionsfromdate, - int? dueDate, - int? cutoffDate, - int? timelimit, - int? sortorder, - }) async { + @override + Future addEssayOverride( + {required int assignid, + int? userId, + int? groupId, + int? allowsubmissionsfromdate, + int? dueDate, + int? cutoffDate, + int? timelimit, + int? sortorder, + int? courseId}) async { if (_userToken == null) throw StateError('User not logged in to Moodle'); final url = Uri.parse('$apiURL$serverUrl'); diff --git a/LearningLens2025/frontend/lib/Api/lms/template/api_singleton.dart b/LearningLens2025/frontend/lib/Api/lms/template/api_singleton.dart index 12e46878..00d46a2c 100644 --- a/LearningLens2025/frontend/lib/Api/lms/template/api_singleton.dart +++ b/LearningLens2025/frontend/lib/Api/lms/template/api_singleton.dart @@ -6,8 +6,10 @@ import 'package:learninglens_app/beans/course.dart'; import 'package:learninglens_app/beans/grade.dart'; import 'package:learninglens_app/beans/lesson_plan.dart'; import 'package:learninglens_app/beans/moodle_rubric.dart'; +import 'package:learninglens_app/beans/override.dart'; import 'package:learninglens_app/beans/participant.dart'; import 'package:learninglens_app/beans/quiz.dart'; +import 'package:learninglens_app/beans/quiz_override'; import 'package:learninglens_app/beans/quiz_type.dart'; import 'package:learninglens_app/beans/submission.dart'; import 'package:learninglens_app/beans/submission_status.dart'; @@ -54,6 +56,9 @@ class ApiSingleton implements LmsInterface { @override List? courses; + @override + List? overrides; + // Authentication/Login methods @override Future login(String username, String password, String baseURL) { @@ -313,4 +318,40 @@ class ApiSingleton implements LmsInterface { {required int assignId}) { throw UnimplementedError(); } + + @override + Future refreshOverrides() { + // TODO: implement refreshOverrides + throw UnimplementedError(); + } + + @override + Future addEssayOverride( + {required int assignid, + int? userId, + int? groupId, + int? allowsubmissionsfromdate, + int? dueDate, + int? cutoffDate, + int? timelimit, + int? sortorder, + int? courseId}) { + // TODO: implement addEssayOverride + throw UnimplementedError(); + } + + @override + Future addQuizOverride( + {required int quizId, + int? userId, + int? groupId, + int? timeOpen, + int? timeClose, + int? timeLimit, + int? attempts, + String? password, + int? courseId}) { + // TODO: implement addQuizOverride + throw UnimplementedError(); + } } diff --git a/LearningLens2025/frontend/lib/Views/g_assignment_create.dart b/LearningLens2025/frontend/lib/Views/g_assignment_create.dart index e76694a3..342476b3 100644 --- a/LearningLens2025/frontend/lib/Views/g_assignment_create.dart +++ b/LearningLens2025/frontend/lib/Views/g_assignment_create.dart @@ -4,14 +4,11 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; import 'package:learninglens_app/Api/lms/factory/lms_factory.dart'; -import 'package:learninglens_app/Api/lms/google_classroom/google_classroom_api.dart'; import 'package:learninglens_app/Api/lms/google_classroom/google_lms_service.dart'; import 'package:learninglens_app/Controller/custom_appbar.dart'; import 'package:learninglens_app/services/local_storage_service.dart'; class CreateAssignmentPage extends StatefulWidget { - final GoogleClassroomApi _googleClassroomApi = GoogleClassroomApi(); - @override _CreateAssignmentPageState createState() => _CreateAssignmentPageState(); } @@ -22,7 +19,7 @@ class _CreateAssignmentPageState extends State { int? _points; DateTime? _dueDate; TimeOfDay? _dueTime; - final String _topic = 'Essay'; // Made static with fixed value + final String _topic = 'essay'; // Made static with fixed value String? _title; String? _instructions; List _courses = []; @@ -110,71 +107,30 @@ class _CreateAssignmentPageState extends State { return; } - final url = Uri.parse( - 'https://classroom.googleapis.com/v1/courses/$_selectedCourseId/courseWork'); - final headers = { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }; - - Map requestBody = { - 'title': _title, - 'description': _instructions, - 'state': 'PUBLISHED', - 'workType': 'ASSIGNMENT', - 'maxPoints': _points, - }; - - if (_dueDate != null && _dueTime != null) { - requestBody['dueDate'] = { - 'year': _dueDate!.year, - 'month': _dueDate!.month, - 'day': _dueDate!.day, - }; - requestBody['dueTime'] = { - 'hours': _dueTime!.hour, - 'minutes': _dueTime!.minute, - 'seconds': 0, - }; - } - - String? topicIdNew = await widget._googleClassroomApi - .getTopicId(_selectedCourseId!, _topic); - if (topicIdNew != null) { - requestBody['topicId'] = topicIdNew; - } - - final body = jsonEncode(requestBody); - - try { - final response = await http.post(url, headers: headers, body: body); - - if (response.statusCode == 200) { - print('Assignment created successfully!'); - await GoogleLmsService() - .courses - ?.firstWhere((c) => c.id.toString() == _selectedCourseId) - .refreshQuizzes(); - Navigator.pop(context); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: - Text('Error creating assignment: ${response.statusCode}'), - backgroundColor: Colors.red, - ), - ); - } - } catch (e) { + var ess = await GoogleLmsService().createAssignment( + _selectedCourseId!, + "", + _title!, + "", + _dueDate?.millisecondsSinceEpoch.toString() ?? "", + _points?.toString() ?? "", + _instructions ?? ""); + if (ess != null) { + print('Assignment created successfully!'); + await GoogleLmsService() + .courses + ?.firstWhere((c) => c.id.toString() == _selectedCourseId) + .refreshEssays(); + Navigator.pop(context); + } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Network error: ${e.toString()}'), + content: Text('Error creating assignment.'), backgroundColor: Colors.red, ), ); - } finally { - setState(() => _isSubmitting = false); } + setState(() => _isSubmitting = false); } } diff --git a/LearningLens2025/frontend/lib/Views/iep_page.dart b/LearningLens2025/frontend/lib/Views/iep_page.dart index afef7f97..044c9886 100644 --- a/LearningLens2025/frontend/lib/Views/iep_page.dart +++ b/LearningLens2025/frontend/lib/Views/iep_page.dart @@ -11,7 +11,6 @@ import 'package:learninglens_app/Api/llm/llm_api_modules_base.dart'; import 'package:learninglens_app/Api/llm/openai_api.dart'; import 'package:learninglens_app/Api/llm/perplexity_api.dart'; import "package:learninglens_app/Api/lms/factory/lms_factory.dart"; -import "package:learninglens_app/Api/lms/moodle/moodle_lms_service.dart"; import "package:learninglens_app/Controller/custom_appbar.dart"; import 'package:learninglens_app/Controller/html_converter.dart'; import 'package:learninglens_app/beans/assessment.dart'; @@ -61,7 +60,7 @@ class _IepPageState extends State { @override void initState() { super.initState(); - overrides = MoodleLmsService().overrides; + overrides = LmsFactory.getLmsService().overrides; overrides?.sort((a, b) => a.fullname.compareTo(b.fullname)); selectedLLM = LlmType.values .firstWhereOrNull((llm) => LocalStorageService.userHasLlmKey(llm)); @@ -561,14 +560,22 @@ class _IepPageState extends State { attempts != null) && (selectedAssignment?.type != "essay" || epochTime2 != null) - ? () { + ? () async { if (selectedAssignment?.type == 'quiz') { - quizOver(epochTime!, selectedAssignment!.id, - userId!, attempts!); + await quizOver( + epochTime!, + int.parse(selectedCourse!), + selectedAssignment!.id, + userId!, + attempts!); } else if (selectedAssignment?.type == 'essay') { - essayOver(epochTime!, selectedAssignment!.id, - userId!, epochTime2!); + await essayOver( + epochTime!, + int.parse(selectedCourse!), + selectedAssignment!.id, + userId!, + epochTime2!); } resetForm(false); } @@ -697,13 +704,14 @@ class _IepPageState extends State { List? getAllCourses() { List? result; - result = MoodleLmsService().courses; + result = LmsFactory.getLmsService().courses; return result; } Future>? getAllParticipants(String courseID) async { List? participants; - participants = await MoodleLmsService().getCourseParticipants(courseID); + participants = + await LmsFactory.getLmsService().getCourseParticipants(courseID); return participants; } @@ -723,11 +731,12 @@ class _IepPageState extends State { Future> handleAssessmentSelection(int? courseID) async { if (courseID != null) { - List essayList = await MoodleLmsService().getEssays(courseID); + List essayList = + await LmsFactory.getLmsService().getEssays(courseID); // Fetch quizzes (if available). List quizList = []; try { - quizList = await MoodleLmsService().getQuizzes(courseID); + quizList = await LmsFactory.getLmsService().getQuizzes(courseID); } catch (e) { print("getQuizzes not available or failed: $e"); } @@ -760,15 +769,17 @@ class _IepPageState extends State { }); } - void quizOver(int epochTime, int quizId, int userId, int attempts) async { - await MoodleLmsService().addQuizOverride( + Future quizOver( + int epochTime, int courseId, int quizId, int userId, int attempts) async { + await LmsFactory.getLmsService().addQuizOverride( quizId: quizId, + courseId: courseId, userId: userId, timeClose: epochTime, attempts: attempts); - await MoodleLmsService().refreshOverrides(); + await LmsFactory.getLmsService().refreshOverrides(); setState(() { - overrides = MoodleLmsService().overrides; + overrides = LmsFactory.getLmsService().overrides; overrides?.sort((a, b) => a.fullname.compareTo(b.fullname)); }); ScaffoldMessenger.of(context).showSnackBar( @@ -776,15 +787,17 @@ class _IepPageState extends State { ); } - void essayOver(int epochTime, int essayId, int userId, int epochTime2) async { - await MoodleLmsService().addEssayOverride( + Future essayOver(int epochTime, int courseId, int essayId, int userId, + int epochTime2) async { + await LmsFactory.getLmsService().addEssayOverride( assignid: essayId, + courseId: courseId, userId: userId, dueDate: epochTime, cutoffDate: epochTime2); - await MoodleLmsService().refreshOverrides(); + await LmsFactory.getLmsService().refreshOverrides(); setState(() { - overrides = MoodleLmsService().overrides; + overrides = LmsFactory.getLmsService().overrides; overrides?.sort((a, b) => a.fullname.compareTo(b.fullname)); }); ScaffoldMessenger.of(context).showSnackBar( diff --git a/LearningLens2025/frontend/lib/beans/assignment.dart b/LearningLens2025/frontend/lib/beans/assignment.dart index 1ee20924..f763de31 100644 --- a/LearningLens2025/frontend/lib/beans/assignment.dart +++ b/LearningLens2025/frontend/lib/beans/assignment.dart @@ -15,6 +15,9 @@ class Assignment implements LearningLensInterface { final List? submissionsWithGrades; + List individualStudentsOptions = []; + int? maxScore; + Assignment({ required this.id, required this.name, @@ -67,7 +70,7 @@ class Assignment implements LearningLensInterface { @override Assignment fromGoogleJson(Map json) { - return Assignment( + Assignment a = Assignment( id: int.parse(json['id']), name: json['title'] ?? 'Untitled', description: json['description'] ?? '', @@ -87,6 +90,13 @@ class Assignment implements LearningLensInterface { gradingStatus: 0, // TODO: figure out grading status courseId: int.parse(json['courseId']), ); + if (json['AssigneeMode']?.toString() == "INDIVIDUAL_STUDENTS") { + final studentOptions = json["studentIds"] as List; + a.individualStudentsOptions + .addAll(studentOptions.map((e) => int.parse(e.toString()))); + } + a.maxScore = json["maxPoints"]; + return a; } @override diff --git a/LearningLens2025/frontend/lib/beans/quiz.dart b/LearningLens2025/frontend/lib/beans/quiz.dart index 95e69620..92aff8a1 100644 --- a/LearningLens2025/frontend/lib/beans/quiz.dart +++ b/LearningLens2025/frontend/lib/beans/quiz.dart @@ -13,6 +13,8 @@ class Quiz { DateTime? timeOpen; DateTime? timeClose; + + List individualStudentsOptions = []; // Constructor with all optional params. Quiz( {this.name, @@ -100,6 +102,11 @@ class Quiz { print('Debug: DueDate parsed to: ${tmpQuiz.timeClose}'); print('Debug: Quiz object created successfully'); + if (json['AssigneeMode']?.toString() == "INDIVIDUAL_STUDENTS") { + final studentOptions = json["studentIds"] as List; + tmpQuiz.individualStudentsOptions + .addAll(studentOptions.map((e) => int.parse(e.toString()))); + } return tmpQuiz; }