develop #1

Merged
akhdanre merged 104 commits from develop into main 2025-07-10 12:38:53 +07:00
7 changed files with 138 additions and 2 deletions
Showing only changes of commit ca9e9cde7d - Show all commits

View File

@ -7,6 +7,8 @@ class APIEndpoint {
static const String register = "/register";
static const String quiz = "/quiz";
static const String quizAnswer = "/quiz/answer";
static const String userQuiz = "/quiz/user";
static const String quizRecomendation = "/quiz/recomendation";
static const String quizSearch = "/quiz/search";

View File

@ -0,0 +1,31 @@
class AnswerModel {
final int questionIndex;
final dynamic answer; // String, bool, atau int
final bool isCorrect;
final double timeSpent;
AnswerModel({
required this.questionIndex,
required this.answer,
required this.isCorrect,
required this.timeSpent,
});
factory AnswerModel.fromJson(Map<String, dynamic> json) {
return AnswerModel(
questionIndex: json['question_index'],
answer: json['answer'],
isCorrect: json['is_correct'],
timeSpent: (json['time_spent'] as num).toDouble(),
);
}
Map<String, dynamic> toJson() {
return {
'question_index': questionIndex,
'answer': answer,
'is_correct': isCorrect,
'time_spent': timeSpent,
};
}
}

View File

@ -0,0 +1,37 @@
import 'package:quiz_app/data/models/answer/answer_model.dart';
class QuizAnswerSubmissionModel {
final String sessionId;
final String quizId;
final String userId;
final DateTime answeredAt;
final List<AnswerModel> answers;
QuizAnswerSubmissionModel({
required this.sessionId,
required this.quizId,
required this.userId,
required this.answeredAt,
required this.answers,
});
factory QuizAnswerSubmissionModel.fromJson(Map<String, dynamic> json) {
return QuizAnswerSubmissionModel(
sessionId: json['session_id'],
quizId: json['quiz_id'],
userId: json['user_id'],
answeredAt: DateTime.parse(json['answered_at']),
answers: (json['answers'] as List).map((e) => AnswerModel.fromJson(e)).toList(),
);
}
Map<String, dynamic> toJson() {
return {
'session_id': sessionId,
'quiz_id': quizId,
'user_id': userId,
'answered_at': answeredAt.toIso8601String(),
'answers': answers.map((e) => e.toJson()).toList(),
};
}
}

View File

@ -1,6 +1,7 @@
import 'package:quiz_app/data/models/quiz/question/base_qustion_model.dart';
class QuizData {
final String id;
final String authorId;
final String subjectId;
final String subjectName;
@ -14,6 +15,7 @@ class QuizData {
final List<BaseQuestionModel> questionListings;
QuizData({
required this.id,
required this.authorId,
required this.subjectId,
required this.subjectName,
@ -29,6 +31,7 @@ class QuizData {
factory QuizData.fromJson(Map<String, dynamic> json) {
return QuizData(
id: json["id"],
authorId: json['author_id'],
subjectId: json['subject_id'],
subjectName: json['subject_alias'],
@ -45,6 +48,7 @@ class QuizData {
Map<String, dynamic> toJson() {
return {
'id': id,
'author_id': authorId,
'subject_id': subjectId,
'subject_alias': subjectName,

View File

@ -0,0 +1,28 @@
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:quiz_app/core/endpoint/api_endpoint.dart';
import 'package:quiz_app/core/utils/logger.dart';
import 'package:quiz_app/data/models/base/base_model.dart';
import 'package:quiz_app/data/providers/dio_client.dart';
class AnswerService extends GetxService {
late final Dio _dio;
@override
void onInit() {
_dio = Get.find<ApiClient>().dio;
super.onInit();
}
Future<BaseResponseModel?> submitQuizAnswers(Map<String, dynamic> payload) async {
try {
await _dio.post(
APIEndpoint.quizAnswer,
data: payload,
);
} on DioException catch (e) {
logC.e('Gagal mengirim jawaban: ${e.response?.data['message'] ?? e.message}');
return null;
}
}
}

View File

@ -1,9 +1,15 @@
import 'package:get/get.dart';
import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/services/answer_service.dart';
import 'package:quiz_app/feature/quiz_play/controller/quiz_play_controller.dart';
class QuizPlayBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<QuizPlayController>(() => QuizPlayController());
Get.lazyPut(() => AnswerService());
Get.lazyPut<QuizPlayController>(() => QuizPlayController(
Get.find<AnswerService>(),
Get.find<UserController>(),
));
}
}

View File

@ -4,13 +4,21 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/component/notification/pop_up_confirmation.dart';
import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/models/answer/answer_model.dart';
import 'package:quiz_app/data/models/quiz/library_quiz_model.dart';
import 'package:quiz_app/data/models/quiz/question/base_qustion_model.dart';
import 'package:quiz_app/data/models/quiz/question/fill_in_the_blank_question_model.dart';
import 'package:quiz_app/data/models/quiz/question/option_question_model.dart';
import 'package:quiz_app/data/models/quiz/question/true_false_question_model.dart';
import 'package:quiz_app/data/services/answer_service.dart';
class QuizPlayController extends GetxController {
final AnswerService _answerService;
final UserController _userController;
QuizPlayController(this._answerService, this._userController);
late final QuizData quizData;
// State & UI
@ -152,8 +160,28 @@ class QuizPlayController extends GetxController {
AppDialog.showMessage(Get.context!, "Yeay semua soal selesai");
await Future.delayed(Duration(seconds: 2));
// Kirim data ke server
try {
await _answerService.submitQuizAnswers({
"session_id": "", // Sesuaikan logika session ID
"quiz_id": quizData.id,
"user_id": _userController.userData!.id, // Asumsikan ini ada di model `QuizData`
"answered_at": DateTime.now().toIso8601String(),
"answers": answeredQuestions.map((answered) {
return AnswerModel(
questionIndex: answered.questionIndex,
answer: answered.selectedAnswer,
isCorrect: answered.isCorrect,
timeSpent: answered.duration.toDouble(),
);
}).toList(),
});
} catch (e) {
AppDialog.showMessage(Get.context!, "Gagal mengirim jawaban: $e");
return;
}
await Future.delayed(const Duration(seconds: 2));
Get.offAllNamed(
AppRoutes.resultQuizPage,