diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index b239b4b..9eb7d68 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -82,5 +82,7 @@ "save_quiz": "Save Quiz", "select_language": "Select Language", - "change_language": "Change Language" + "change_language": "Change Language", + + "auto_generate_quiz": "Auto Generate Quiz" } diff --git a/assets/translations/id-ID.json b/assets/translations/id-ID.json index 345ee7d..cef3637 100644 --- a/assets/translations/id-ID.json +++ b/assets/translations/id-ID.json @@ -82,5 +82,6 @@ "save_quiz": "Simpan Kuis", "select_language": "Pilih Bahasa", - "change_language": "Ganti Bahasa" + "change_language": "Ganti Bahasa", + "auto_generate_quiz": "Buat Kuis Otomatis" } diff --git a/assets/translations/ms-MY.json b/assets/translations/ms-MY.json index a5ec604..9cbc487 100644 --- a/assets/translations/ms-MY.json +++ b/assets/translations/ms-MY.json @@ -79,5 +79,7 @@ "quiz_description_label": "Deskripsi Ringkas", "quiz_subject_label": "Subjek", "make_quiz_public": "Jadikan Kuiz Umum", - "save_quiz": "Simpan Kuiz" + "save_quiz": "Simpan Kuiz", + + "auto_generate_quiz": "Jana Kuiz Automatik" } diff --git a/lib/app/app.dart b/lib/app/app.dart index a2c3a11..e1cf154 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -16,7 +16,7 @@ class MyApp extends StatelessWidget { localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, initialBinding: InitialBindings(), - initialRoute: AppRoutes.monitorResultMPLPage, + initialRoute: AppRoutes.splashScreen, getPages: AppPages.routes, ); } diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 0713c02..692f6e5 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -37,7 +37,6 @@ import 'package:quiz_app/feature/search/binding/search_binding.dart'; import 'package:quiz_app/feature/splash_screen/presentation/splash_screen_page.dart'; import 'package:quiz_app/feature/waiting_room/binding/waiting_room_binding.dart'; import 'package:quiz_app/feature/waiting_room/view/waiting_room_view.dart'; -import 'package:quiz_app/feature/admin_result_page/view/admin_result_page.dart'; part 'app_routes.dart'; @@ -136,9 +135,9 @@ class AppPages { page: () => PlayQuizMultiplayerView(), binding: PlayQuizMultiplayerBinding(), ), - GetPage( - name: AppRoutes.monitorResultMPLPage, - page: () => AdminResultPage(), - ) + // GetPage( + // name: AppRoutes.monitorResultMPLPage, + // page: () => AdminResultPage(), + // ) ]; } diff --git a/lib/core/endpoint/api_endpoint.dart b/lib/core/endpoint/api_endpoint.dart index 2188098..cab3205 100644 --- a/lib/core/endpoint/api_endpoint.dart +++ b/lib/core/endpoint/api_endpoint.dart @@ -9,6 +9,7 @@ class APIEndpoint { static const String register = "/register"; static const String quiz = "/quiz"; + static const String quizGenerate = "/quiz/ai"; static const String quizAnswer = "/quiz/answer"; static const String userQuiz = "/quiz/user"; diff --git a/lib/data/services/quiz_service.dart b/lib/data/services/quiz_service.dart index b92358d..c1146fe 100644 --- a/lib/data/services/quiz_service.dart +++ b/lib/data/services/quiz_service.dart @@ -35,6 +35,32 @@ class QuizService extends GetxService { } } + Future>> createQuizAuto(String sentence) async { + try { + final response = await _dio.post( + APIEndpoint.quizGenerate, + data: {"sentence": sentence}, + ); + + if (response.statusCode == 200) { + print(response.data); + + // Parsing response using BaseResponseModel + final parseResponse = BaseResponseModel>.fromJson( + response.data, + (data) => (data as List).map((item) => RawQuizModel.fromJson(item as Map)).toList(), + ); + + return parseResponse; + } else { + throw Exception("Quiz creation failed with status: ${response.statusCode}"); + } + } catch (e) { + logC.e("Quiz creation error: $e"); + throw Exception("Quiz creation error: $e"); + } + } + Future>?> userQuiz(String userId, int page) async { try { final response = await _dio.get("${APIEndpoint.userQuiz}/$userId?page=$page"); @@ -122,3 +148,27 @@ class QuizService extends GetxService { } } } + +class RawQuizModel { + final String qustion; + final dynamic answer; + + RawQuizModel({ + required this.qustion, + required this.answer, + }); + + factory RawQuizModel.fromJson(Map json) { + return RawQuizModel( + qustion: json['qustion'] as String, + answer: json['answer'], + ); + } + + Map toJson() { + return { + 'qustion': qustion, + 'answer': answer, + }; + } +} diff --git a/lib/feature/quiz_creation/binding/quiz_creation_binding.dart b/lib/feature/quiz_creation/binding/quiz_creation_binding.dart index 4c3154a..8fd8031 100644 --- a/lib/feature/quiz_creation/binding/quiz_creation_binding.dart +++ b/lib/feature/quiz_creation/binding/quiz_creation_binding.dart @@ -1,9 +1,15 @@ import "package:get/get.dart"; +import "package:quiz_app/data/services/quiz_service.dart"; import "package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart"; class QuizCreationBinding extends Bindings { @override void dependencies() { - Get.lazyPut(() => QuizCreationController()); + Get.lazyPut(() => QuizService()); + Get.lazyPut( + () => QuizCreationController( + Get.find(), + ), + ); } } diff --git a/lib/feature/quiz_creation/controller/quiz_creation_controller.dart b/lib/feature/quiz_creation/controller/quiz_creation_controller.dart index 5d72a76..d4a3914 100644 --- a/lib/feature/quiz_creation/controller/quiz_creation_controller.dart +++ b/lib/feature/quiz_creation/controller/quiz_creation_controller.dart @@ -5,9 +5,18 @@ import 'package:quiz_app/app/const/enums/question_type.dart'; import 'package:quiz_app/app/routes/app_pages.dart'; import 'package:quiz_app/component/notification/delete_confirmation.dart'; import 'package:quiz_app/component/notification/pop_up_confirmation.dart'; +import 'package:quiz_app/core/utils/custom_floating_loading.dart'; +import 'package:quiz_app/core/utils/logger.dart'; +import 'package:quiz_app/data/models/base/base_model.dart'; import 'package:quiz_app/data/models/quiz/quiestion_data_model.dart'; +import 'package:quiz_app/data/services/quiz_service.dart'; class QuizCreationController extends GetxController { + final QuizService _quizService; + + QuizCreationController(this._quizService); + + final TextEditingController inputSentenceTC = TextEditingController(); final TextEditingController questionTC = TextEditingController(); final TextEditingController answerTC = TextEditingController(); final List optionTCList = List.generate(4, (_) => TextEditingController()); @@ -213,4 +222,56 @@ class QuizCreationController extends GetxController { selectedQuizIndex.value -= 1; } } + + void generateQuiz() async { + CustomFloatingLoading.showLoadingDialog(Get.context!); + + try { + BaseResponseModel> response = await _quizService.createQuizAuto(inputSentenceTC.text); + + if (response.data != null) { + final previousLength = quizData.length; + + if (previousLength == 1) quizData.removeAt(0); + + for (final i in response.data!) { + QuestionType type = QuestionType.fillTheBlank; + + if (i.answer.toString().toLowerCase() == 'true' || i.answer.toString().toLowerCase() == 'false') { + type = QuestionType.trueOrFalse; + } + + quizData.add(QuestionData( + index: quizData.length + 1, + question: i.qustion, + answer: i.answer, + type: type, + )); + } + + if (response.data!.isNotEmpty) { + selectedQuizIndex.value = previousLength; + final data = quizData[selectedQuizIndex.value]; + questionTC.text = data.question ?? ""; + answerTC.text = data.answer ?? ""; + currentDuration.value = data.duration; + currentQuestionType.value = data.type ?? QuestionType.fillTheBlank; + return; + } + } + } catch (e) { + logC.e("Error while generating quiz: $e"); + } finally { + CustomFloatingLoading.hideLoadingDialog(Get.context!); + isGenerate.value = false; + + if (quizData.isNotEmpty && selectedQuizIndex.value == 0) { + final data = quizData[0]; + questionTC.text = data.question ?? ""; + answerTC.text = data.answer ?? ""; + currentDuration.value = data.duration; + currentQuestionType.value = data.type ?? QuestionType.fillTheBlank; + } + } + } } diff --git a/lib/feature/quiz_creation/view/component/custom_question_component.dart b/lib/feature/quiz_creation/view/component/custom_question_component.dart index c543240..17fe6da 100644 --- a/lib/feature/quiz_creation/view/component/custom_question_component.dart +++ b/lib/feature/quiz_creation/view/component/custom_question_component.dart @@ -1,7 +1,9 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:quiz_app/app/const/colors/app_colors.dart'; import 'package:quiz_app/app/const/enums/question_type.dart'; +import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart'; import 'package:quiz_app/feature/quiz_creation/view/component/fill_the_blank_component.dart'; import 'package:quiz_app/feature/quiz_creation/view/component/option_question_component.dart'; @@ -30,6 +32,11 @@ class CustomQuestionComponent extends GetView { _questionTypeValue(), const SizedBox(height: 20), _buildDurationDropdown(), + const SizedBox(height: 30), + GlobalButton( + text: context.tr('save_all'), + onPressed: controller.onDone, + ) ], ); } diff --git a/lib/feature/quiz_creation/view/component/generate_component.dart b/lib/feature/quiz_creation/view/component/generate_component.dart index 70ef06a..04b8b2f 100644 --- a/lib/feature/quiz_creation/view/component/generate_component.dart +++ b/lib/feature/quiz_creation/view/component/generate_component.dart @@ -1,17 +1,19 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:quiz_app/component/global_button.dart'; +import 'package:quiz_app/component/global_text_field.dart'; import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart'; class GenerateComponent extends GetView { const GenerateComponent({super.key}); - @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( - "Unggah file materi kamu (PDF atau Word) untuk membuat soal otomatis.", + "Masukkan paragraf untuk dijadikan soal", style: TextStyle( fontSize: 14, color: Color(0xFF6B778C), @@ -19,41 +21,16 @@ class GenerateComponent extends GetView { ), ), const SizedBox(height: 16), - GestureDetector( - onTap: () {}, - child: Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(vertical: 30), - decoration: BoxDecoration( - color: const Color(0xFFF0F2F5), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade300), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Icon(Icons.insert_drive_file, size: 50, color: Color(0xFF6B778C)), - SizedBox(height: 10), - Text( - "Upload PDF atau Word", - style: TextStyle( - fontSize: 16, - color: Color(0xFF6B778C), - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 8), - Text( - "Max 10 MB", - style: TextStyle( - fontSize: 12, - color: Color(0xFF9FA8B2), - ), - ), - ], - ), - ), + GlobalTextField( + hintText: "Tulis kalimat atau paragraf panjang, dan kami akan mengubahnya menjadi soal secara otomatis", + controller: controller.inputSentenceTC, + limitTextLine: 15, ), + const SizedBox(height: 16), + GlobalButton( + text: context.tr('auto_generate_quiz'), + onPressed: controller.generateQuiz, + ) ], ); } diff --git a/lib/feature/quiz_creation/view/quiz_creation_view.dart b/lib/feature/quiz_creation/view/quiz_creation_view.dart index 53dcefd..114db26 100644 --- a/lib/feature/quiz_creation/view/quiz_creation_view.dart +++ b/lib/feature/quiz_creation/view/quiz_creation_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:quiz_app/app/const/colors/app_colors.dart'; -import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart'; import 'package:quiz_app/feature/quiz_creation/view/component/custom_question_component.dart'; import 'package:quiz_app/feature/quiz_creation/view/component/generate_component.dart'; @@ -40,11 +39,6 @@ class QuizCreationView extends GetView { _buildModeSelector(context), const SizedBox(height: 20), Obx(() => controller.isGenerate.value ? const GenerateComponent() : const CustomQuestionComponent()), - const SizedBox(height: 30), - GlobalButton( - text: context.tr('save_all'), - onPressed: controller.onDone, - ) ], ), ),