fix: make the quiz answer component into global

This commit is contained in:
akhdanre 2025-05-04 22:06:02 +07:00
parent 55d96c3baf
commit 1a465fd0d1
4 changed files with 154 additions and 143 deletions

View File

@ -1,156 +1,156 @@
import 'package:flutter/material.dart'; // import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart'; // import 'package:lucide_icons/lucide_icons.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart'; // import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/app/const/text/text_style.dart'; // import 'package:quiz_app/app/const/text/text_style.dart';
import 'package:quiz_app/data/models/history/detail_quiz_history.dart'; // import 'package:quiz_app/data/models/history/detail_quiz_history.dart';
class QuizItemComponent extends StatelessWidget { // class QuizItemComponent extends StatelessWidget {
final QuestionAnswerItem item; // final QuestionAnswerItem item;
const QuizItemComponent({super.key, required this.item}); // const QuizItemComponent({super.key, required this.item});
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
final bool isOptionType = item.type == 'option'; // final bool isOptionType = item.type == 'option';
return Container( // return Container(
width: double.infinity, // width: double.infinity,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), // margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: const EdgeInsets.all(20), // padding: const EdgeInsets.all(20),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: BorderRadius.circular(16), // borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.black.withValues(alpha: 0.04), // color: Colors.black.withValues(alpha: 0.04),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 2), // offset: const Offset(0, 2),
), // ),
], // ],
), // ),
child: Column( // child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
_buildQuestionText(), // _buildQuestionText(),
const SizedBox(height: 16), // const SizedBox(height: 16),
if (isOptionType && item.options != null) _buildOptions(), // if (isOptionType && item.options != null) _buildOptions(),
const SizedBox(height: 12), // const SizedBox(height: 12),
_buildAnswerIndicator(), // _buildAnswerIndicator(),
const SizedBox(height: 16), // const SizedBox(height: 16),
const Divider(height: 24, color: AppColors.shadowPrimary), // const Divider(height: 24, color: AppColors.shadowPrimary),
_buildMetadata(), // _buildMetadata(),
], // ],
), // ),
); // );
} // }
Widget _buildQuestionText() { // Widget _buildQuestionText() {
return Text( // return Text(
'${item.index}. ${item.question}', // '${item.index}. ${item.question}',
style: AppTextStyles.title.copyWith(fontSize: 16, fontWeight: FontWeight.w600), // style: AppTextStyles.title.copyWith(fontSize: 16, fontWeight: FontWeight.w600),
); // );
} // }
Widget _buildOptions() { // Widget _buildOptions() {
return Column( // return Column(
children: item.options!.asMap().entries.map((entry) { // children: item.options!.asMap().entries.map((entry) {
final int index = entry.key; // final int index = entry.key;
final String text = entry.value; // final String text = entry.value;
final bool isCorrectAnswer = index == item.targetAnswer; // final bool isCorrectAnswer = index == item.targetAnswer;
final bool isUserWrongAnswer = index == item.userAnswer && !isCorrectAnswer; // final bool isUserWrongAnswer = index == item.userAnswer && !isCorrectAnswer;
Color? backgroundColor; // Color? backgroundColor;
IconData icon = LucideIcons.circle; // IconData icon = LucideIcons.circle;
Color iconColor = AppColors.shadowPrimary; // Color iconColor = AppColors.shadowPrimary;
if (isCorrectAnswer) { // if (isCorrectAnswer) {
backgroundColor = AppColors.primaryBlue.withValues(alpha: 0.15); // backgroundColor = AppColors.primaryBlue.withValues(alpha: 0.15);
icon = LucideIcons.checkCircle2; // icon = LucideIcons.checkCircle2;
iconColor = AppColors.primaryBlue; // iconColor = AppColors.primaryBlue;
} else if (isUserWrongAnswer) { // } else if (isUserWrongAnswer) {
backgroundColor = Colors.red.withValues(alpha: 0.15); // backgroundColor = Colors.red.withValues(alpha: 0.15);
icon = LucideIcons.xCircle; // icon = LucideIcons.xCircle;
iconColor = Colors.red; // iconColor = Colors.red;
} // }
return Container( // return Container(
width: double.infinity, // width: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 6), // margin: const EdgeInsets.symmetric(vertical: 6),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), // padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: backgroundColor, // color: backgroundColor,
borderRadius: BorderRadius.circular(12), // borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.shadowPrimary), // border: Border.all(color: AppColors.shadowPrimary),
), // ),
child: Row( // child: Row(
children: [ // children: [
Icon(icon, size: 16, color: iconColor), // Icon(icon, size: 16, color: iconColor),
const SizedBox(width: 8), // const SizedBox(width: 8),
Flexible( // Flexible(
child: Text(text, style: AppTextStyles.optionText), // child: Text(text, style: AppTextStyles.optionText),
), // ),
], // ],
), // ),
); // );
}).toList(), // }).toList(),
); // );
} // }
Widget _buildAnswerIndicator() { // Widget _buildAnswerIndicator() {
final correctIcon = item.isCorrect ? LucideIcons.checkCircle2 : LucideIcons.xCircle; // final correctIcon = item.isCorrect ? LucideIcons.checkCircle2 : LucideIcons.xCircle;
final correctColor = item.isCorrect ? AppColors.primaryBlue : Colors.red; // final correctColor = item.isCorrect ? AppColors.primaryBlue : Colors.red;
final String userAnswerText = item.type == 'option' ? item.options![item.userAnswer] : item.userAnswer.toString(); // final String userAnswerText = item.type == 'option' ? item.options![item.userAnswer] : item.userAnswer.toString();
final String correctAnswerText = item.targetAnswer.toString(); // final String correctAnswerText = item.targetAnswer.toString();
return Column( // return Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
Row( // Row(
children: [ // children: [
Icon(correctIcon, color: correctColor, size: 18), // Icon(correctIcon, color: correctColor, size: 18),
const SizedBox(width: 8), // const SizedBox(width: 8),
Text( // Text(
'Jawabanmu: $userAnswerText', // 'Jawabanmu: $userAnswerText',
style: AppTextStyles.statValue, // style: AppTextStyles.statValue,
), // ),
], // ],
), // ),
if (item.type != 'option' && !item.isCorrect) ...[ // if (item.type != 'option' && !item.isCorrect) ...[
const SizedBox(height: 6), // const SizedBox(height: 6),
Row( // Row(
children: [ // children: [
const SizedBox(width: 26), // offset for icon + spacing // const SizedBox(width: 26), // offset for icon + spacing
Text( // Text(
'Jawaban benar: $correctAnswerText', // 'Jawaban benar: $correctAnswerText',
style: AppTextStyles.caption, // style: AppTextStyles.caption,
), // ),
], // ],
), // ),
], // ],
], // ],
); // );
} // }
Widget _buildMetadata() { // Widget _buildMetadata() {
return Row( // return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ // children: [
_metaItem(icon: LucideIcons.helpCircle, label: item.type), // _metaItem(icon: LucideIcons.helpCircle, label: item.type),
_metaItem(icon: LucideIcons.clock3, label: '${item.timeSpent}s'), // _metaItem(icon: LucideIcons.clock3, label: '${item.timeSpent}s'),
], // ],
); // );
} // }
Widget _metaItem({required IconData icon, required String label}) { // Widget _metaItem({required IconData icon, required String label}) {
return Row( // return Row(
children: [ // children: [
Icon(icon, size: 16, color: AppColors.primaryBlue), // Icon(icon, size: 16, color: AppColors.primaryBlue),
const SizedBox(width: 6), // const SizedBox(width: 6),
Text(label, style: AppTextStyles.caption), // Text(label, style: AppTextStyles.caption),
], // ],
); // );
} // }
} // }

View File

@ -4,8 +4,8 @@ import 'package:lucide_icons/lucide_icons.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart'; import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/app/const/text/text_style.dart'; import 'package:quiz_app/app/const/text/text_style.dart';
import 'package:quiz_app/component/widget/loading_widget.dart'; import 'package:quiz_app/component/widget/loading_widget.dart';
import 'package:quiz_app/component/widget/quiz_item_wa_component.dart';
import 'package:quiz_app/feature/history/controller/detail_history_controller.dart'; import 'package:quiz_app/feature/history/controller/detail_history_controller.dart';
import 'package:quiz_app/feature/history/view/component/quiz_item_component.dart';
class DetailHistoryView extends GetView<DetailHistoryController> { class DetailHistoryView extends GetView<DetailHistoryController> {
const DetailHistoryView({super.key}); const DetailHistoryView({super.key});
@ -41,7 +41,18 @@ class DetailHistoryView extends GetView<DetailHistoryController> {
} }
List<Widget> quizListings() { List<Widget> quizListings() {
return controller.quizAnswer.questionListings.map((e) => QuizItemComponent(item: e)).toList(); return controller.quizAnswer.questionListings
.map((e) => QuizItemWAComponent(
index: e.index,
isCorrect: e.isCorrect,
question: e.question,
targetAnswer: e.targetAnswer,
timeSpent: e.timeSpent,
type: e.type,
userAnswer: e.userAnswer,
options: e.options,
))
.toList();
} }
Widget quizMetaInfo() { Widget quizMetaInfo() {

View File

@ -6,7 +6,7 @@ import 'package:quiz_app/data/models/quiz/question/fill_in_the_blank_question_mo
import 'package:quiz_app/data/models/quiz/question/option_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/models/quiz/question/true_false_question_model.dart';
import 'package:quiz_app/feature/quiz_result/controller/quiz_result_controller.dart'; import 'package:quiz_app/feature/quiz_result/controller/quiz_result_controller.dart';
import 'package:quiz_app/feature/quiz_result/view/component/quiz_item_wa_component.dart'; import 'package:quiz_app/component/widget/quiz_item_wa_component.dart';
class QuizResultView extends GetView<QuizResultController> { class QuizResultView extends GetView<QuizResultController> {
const QuizResultView({super.key}); const QuizResultView({super.key});