diff --git a/lib/app/app.dart b/lib/app/app.dart index e1cf154..a2c3a11 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.splashScreen, + initialRoute: AppRoutes.monitorResultMPLPage, getPages: AppPages.routes, ); } diff --git a/lib/app/const/colors/app_colors.dart b/lib/app/const/colors/app_colors.dart index 2e8cf87..203044e 100644 --- a/lib/app/const/colors/app_colors.dart +++ b/lib/app/const/colors/app_colors.dart @@ -11,4 +11,9 @@ class AppColors { static const Color shadowPrimary = Color(0x330052CC); static const Color disabledBackground = Color(0xFFE0E0E0); static const Color disabledText = Color(0xFF9E9E9E); + + static const Color scoreExcellent = Color(0xFF36B37E); + static const Color scoreGood = Color(0xFF00B8D9); + static const Color scoreAverage = Color(0xFFFF991F); + static const Color scorePoor = Color(0xFFFF5630); } diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index ea622f2..0713c02 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -37,6 +37,7 @@ 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'; @@ -135,5 +136,9 @@ class AppPages { page: () => PlayQuizMultiplayerView(), binding: PlayQuizMultiplayerBinding(), ), + GetPage( + name: AppRoutes.monitorResultMPLPage, + page: () => AdminResultPage(), + ) ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index 3274125..3410b5d 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -24,4 +24,5 @@ abstract class AppRoutes { static const playQuizMPLPage = "/room/quiz/play"; static const monitorQuizMPLPage = "/room/quiz/monitor"; + static const monitorResultMPLPage = "/room/quiz/monitor/result"; } diff --git a/lib/feature/admin_result_page/view/admin_result_page.dart b/lib/feature/admin_result_page/view/admin_result_page.dart new file mode 100644 index 0000000..1232724 --- /dev/null +++ b/lib/feature/admin_result_page/view/admin_result_page.dart @@ -0,0 +1,263 @@ +// import 'package:flutter/material.dart'; +// import 'package:lucide_icons/lucide_icons.dart'; +// import 'dart:math' as math; + +// import 'package:quiz_app/app/const/colors/app_colors.dart'; +// import 'package:quiz_app/app/const/text/text_style.dart'; +// import 'package:quiz_app/feature/admin_result_page/view/detail_participant_result_page.dart'; + +// class AdminResultPage extends StatelessWidget { +// const AdminResultPage({Key? key}) : super(key: key); + +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: AppColors.background, +// body: SafeArea( +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// _buildSectionHeader("Hasil Akhir Kuis"), +// _buildSummaryCard(), +// const SizedBox(height: 20), +// _buildSectionHeader('Peringkat Peserta'), +// const SizedBox(height: 14), +// Expanded( +// child: ListView.separated( +// itemCount: dummyParticipants.length, +// separatorBuilder: (context, index) => const SizedBox(height: 10), +// itemBuilder: (context, index) { +// final participant = dummyParticipants[index]; +// return _buildParticipantResultCard( +// context, +// participant, +// position: index + 1, +// ); +// }, +// ), +// ), +// ], +// ), +// ), +// ), +// ); +// } + +// Widget _buildSectionHeader(String title) { +// return Container( +// padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(8), +// ), +// child: Text(title, style: AppTextStyles.title), +// ); +// } + +// Widget _buildSummaryCard() { +// // Hitung nilai rata-rata +// final avgScore = dummyParticipants.map((p) => p.scorePercent).reduce((a, b) => a + b) / dummyParticipants.length; + +// // Hitung jumlah peserta yang lulus (>= 60%) +// final passCount = dummyParticipants.where((p) => p.scorePercent >= 60).length; + +// return Card( +// elevation: 2, +// color: Colors.white, +// shadowColor: AppColors.shadowPrimary.withOpacity(0.2), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(16), +// side: BorderSide(color: AppColors.accentBlue.withOpacity(0.2)), +// ), +// child: Padding( +// padding: const EdgeInsets.all(20), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// children: [ +// Icon( +// LucideIcons.clipboardCheck, +// color: AppColors.primaryBlue, +// size: 20, +// ), +// const SizedBox(width: 8), +// Text( +// "RINGKASAN KUIS", +// style: TextStyle( +// fontSize: 13, +// fontWeight: FontWeight.bold, +// color: AppColors.primaryBlue, +// letterSpacing: 0.8, +// ), +// ), +// ], +// ), +// Divider(color: AppColors.borderLight, height: 20), +// Row( +// mainAxisAlignment: MainAxisAlignment.spaceAround, +// children: [ +// _buildSummaryItem( +// icon: LucideIcons.users, +// value: "${dummyParticipants.length}", +// label: "Total Peserta", +// ), +// _buildSummaryItem( +// icon: LucideIcons.percent, +// value: "${avgScore.toStringAsFixed(1)}%", +// label: "Rata-Rata Nilai", +// valueColor: _getScoreColor(avgScore), +// ), +// _buildSummaryItem( +// icon: LucideIcons.award, +// value: "$passCount/${dummyParticipants.length}", +// label: "Peserta Lulus", +// valueColor: AppColors.scoreGood, +// ), +// ], +// ), +// ], +// ), +// ), +// ); +// } + +// Widget _buildSummaryItem({ +// required IconData icon, +// required String value, +// required String label, +// Color? valueColor, +// }) { +// return Column( +// children: [ +// Icon(icon, color: AppColors.softGrayText, size: 22), +// const SizedBox(height: 8), +// Text( +// value, +// style: TextStyle( +// fontSize: 18, +// fontWeight: FontWeight.bold, +// color: valueColor ?? AppColors.darkText, +// ), +// ), +// const SizedBox(height: 4), +// Text( +// label, +// style: AppTextStyles.caption, +// ), +// ], +// ); +// } + +// Widget _buildParticipantResultCard(BuildContext context, ParticipantResult participant, {required int position}) { +// return InkWell( +// onTap: () { +// // Navigasi ke halaman detail saat kartu ditekan +// Navigator.push( +// context, +// MaterialPageRoute( +// builder: (context) => ParticipantDetailPage(participant: participant), +// ), +// ); +// }, +// child: Card( +// elevation: 2, +// color: Colors.white, +// shadowColor: AppColors.shadowPrimary.withOpacity(0.2), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(16), +// side: BorderSide(color: AppColors.accentBlue.withOpacity(0.2)), +// ), +// child: Padding( +// padding: const EdgeInsets.all(20), +// child: Row( +// children: [ +// // Position indicator +// Container( +// width: 36, +// height: 36, +// decoration: BoxDecoration( +// shape: BoxShape.circle, +// color: _getPositionColor(position), +// ), +// child: Center( +// child: Text( +// position.toString(), +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: Colors.white, +// ), +// ), +// ), +// ), +// const SizedBox(width: 16), +// // Participant info +// Expanded( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// participant.name, +// style: AppTextStyles.subtitle, +// ), +// const SizedBox(height: 4), +// Text( +// "Benar: ${participant.correctAnswers}/${participant.totalQuestions}", +// style: AppTextStyles.caption, +// ), +// ], +// ), +// ), +// // Score +// Container( +// width: 60, +// height: 60, +// decoration: BoxDecoration( +// shape: BoxShape.circle, +// color: _getScoreColor(participant.scorePercent).withOpacity(0.1), +// border: Border.all( +// color: _getScoreColor(participant.scorePercent), +// width: 2, +// ), +// ), +// child: Center( +// child: Text( +// "${participant.scorePercent.toInt()}%", +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: _getScoreColor(participant.scorePercent), +// ), +// ), +// ), +// ), +// const SizedBox(width: 12), +// // Arrow indicator +// Icon( +// LucideIcons.chevronRight, +// color: AppColors.softGrayText, +// size: 20, +// ), +// ], +// ), +// ), +// ), +// ); +// } + +// Color _getScoreColor(double score) { +// if (score >= 80) return AppColors.scoreExcellent; +// if (score >= 70) return AppColors.scoreGood; +// if (score >= 60) return AppColors.scoreAverage; +// return AppColors.scorePoor; +// } + +// Color _getPositionColor(int position) { +// if (position == 1) return const Color(0xFFFFD700); // Gold +// if (position == 2) return const Color(0xFFC0C0C0); // Silver +// if (position == 3) return const Color(0xFFCD7F32); // Bronze +// return AppColors.softGrayText; +// } +// } diff --git a/lib/feature/admin_result_page/view/detail_participant_result_page.dart b/lib/feature/admin_result_page/view/detail_participant_result_page.dart new file mode 100644 index 0000000..967011f --- /dev/null +++ b/lib/feature/admin_result_page/view/detail_participant_result_page.dart @@ -0,0 +1,238 @@ +// // Halaman detail untuk peserta +// import 'package:flutter/material.dart'; +// import 'package:lucide_icons/lucide_icons.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/feature/admin_result_page/view/admin_result_page.dart'; + +// class ParticipantDetailPage extends StatelessWidget { +// final ParticipantResult participant; + +// const ParticipantDetailPage({ +// Key? key, +// required this.participant, +// }) : super(key: key); + +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: AppColors.background, +// appBar: AppBar( +// title: Text('Detail ${participant.name}'), +// backgroundColor: Colors.white, +// foregroundColor: AppColors.darkText, +// elevation: 0, +// leading: IconButton( +// icon: const Icon(LucideIcons.arrowLeft), +// onPressed: () => Navigator.pop(context), +// ), +// ), +// body: Column( +// children: [ +// _buildParticipantHeader(), +// Expanded( +// child: ListView.builder( +// padding: const EdgeInsets.all(16), +// itemCount: participant.answers.length, +// itemBuilder: (context, index) { +// return _buildAnswerCard(participant.answers[index], index + 1); +// }, +// ), +// ), +// ], +// ), +// ); +// } + +// Widget _buildParticipantHeader() { +// return Container( +// width: double.infinity, +// padding: const EdgeInsets.all(16), +// decoration: BoxDecoration( +// color: Colors.white, +// border: Border( +// bottom: BorderSide( +// color: AppColors.borderLight, +// width: 1, +// ), +// ), +// ), +// child: Row( +// children: [ +// CircleAvatar( +// radius: 26, +// backgroundColor: AppColors.accentBlue, +// child: Text( +// participant.name.isNotEmpty ? participant.name[0].toUpperCase() : "?", +// style: TextStyle( +// fontSize: 22, +// fontWeight: FontWeight.bold, +// color: AppColors.primaryBlue, +// ), +// ), +// ), +// const SizedBox(width: 16), +// Expanded( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// participant.name, +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: AppColors.darkText, +// ), +// ), +// const SizedBox(height: 4), +// Text( +// "Jumlah Soal: ${participant.totalQuestions}", +// style: TextStyle( +// fontSize: 14, +// color: AppColors.softGrayText, +// ), +// ), +// ], +// ), +// ), +// Container( +// padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), +// decoration: BoxDecoration( +// color: _getScoreColor(participant.scorePercent).withOpacity(0.1), +// borderRadius: BorderRadius.circular(16), +// border: Border.all( +// color: _getScoreColor(participant.scorePercent), +// ), +// ), +// child: Row( +// children: [ +// Icon( +// LucideIcons.percent, +// size: 16, +// color: _getScoreColor(participant.scorePercent), +// ), +// const SizedBox(width: 6), +// Text( +// "${participant.scorePercent.toInt()}%", +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: _getScoreColor(participant.scorePercent), +// ), +// ), +// ], +// ), +// ), +// ], +// ), +// ); +// } + +// Widget _buildAnswerCard(QuestionAnswer answer, int number) { +// return Container( +// width: double.infinity, +// margin: const EdgeInsets.only(bottom: 20), +// padding: const EdgeInsets.all(16), +// // decoration: _containerDecoration, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// width: 28, +// height: 28, +// decoration: BoxDecoration( +// shape: BoxShape.circle, +// color: answer.isCorrect ? AppColors.primaryBlue.withOpacity(0.1) : AppColors.scorePoor.withOpacity(0.1), +// ), +// child: Center( +// child: Text( +// number.toString(), +// style: TextStyle( +// fontSize: 13, +// fontWeight: FontWeight.bold, +// color: answer.isCorrect ? AppColors.primaryBlue : AppColors.scorePoor, +// ), +// ), +// ), +// ), +// const SizedBox(width: 12), +// Expanded( +// child: Text( +// 'Soal $number: ${answer.question}', +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: AppColors.darkText, +// ), +// ), +// ), +// Icon( +// answer.isCorrect ? LucideIcons.checkCircle : LucideIcons.xCircle, +// color: answer.isCorrect ? AppColors.primaryBlue : AppColors.scorePoor, +// size: 20, +// ), +// ], +// ), +// const SizedBox(height: 12), +// Divider(color: AppColors.borderLight), +// const SizedBox(height: 12), +// _buildAnswerRow( +// label: "Jawaban Siswa:", +// answer: answer.userAnswer, +// isCorrect: answer.isCorrect, +// ), +// if (!answer.isCorrect) ...[ +// const SizedBox(height: 10), +// _buildAnswerRow( +// label: "Jawaban Benar:", +// answer: answer.correctAnswer, +// isCorrect: true, +// ), +// ], +// ], +// ), +// ); +// } + +// Widget _buildAnswerRow({ +// required String label, +// required String answer, +// required bool isCorrect, +// }) { +// return Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// SizedBox( +// width: 110, +// child: Text( +// label, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.w500, +// color: AppColors.softGrayText, +// ), +// ), +// ), +// Expanded( +// child: Text( +// answer, +// style: TextStyle( +// fontSize: 15, +// fontWeight: FontWeight.w600, +// color: isCorrect ? AppColors.primaryBlue : AppColors.scorePoor, +// ), +// ), +// ), +// ], +// ); +// } + +// Color _getScoreColor(double score) { +// if (score >= 70) return AppColors.scoreGood; +// if (score >= 60) return AppColors.scoreAverage; +// return AppColors.scorePoor; +// } +// } diff --git a/lib/feature/monitor_quiz/view/monitor_quiz_view.dart b/lib/feature/monitor_quiz/view/monitor_quiz_view.dart index 1c09fb7..32f5570 100644 --- a/lib/feature/monitor_quiz/view/monitor_quiz_view.dart +++ b/lib/feature/monitor_quiz/view/monitor_quiz_view.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:lucide_icons/lucide_icons.dart'; +import 'package:percent_indicator/linear_percent_indicator.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/feature/monitor_quiz/controller/monitor_quiz_controller.dart'; class MonitorQuizView extends GetView { @@ -9,32 +12,115 @@ class MonitorQuizView extends GetView { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Monitor Quiz')), - body: Padding( - padding: const EdgeInsets.all(16.0), + backgroundColor: AppColors.background, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionHeader("Monitor Admin"), + Obx(() => _buildCurrentQuestion( + questionText: controller.currentQuestion.value, + )), + const SizedBox(height: 24), + _buildSectionHeader('Daftar Peserta'), + const SizedBox(height: 16), + Expanded( + child: Obx( + () => ListView.separated( + itemCount: controller.participan.length, + separatorBuilder: (context, index) => const SizedBox(height: 12), + itemBuilder: (context, index) { + final student = controller.participan[index]; + final totalAnswers = student.correct.value + student.wrong.value; + final progressPercent = totalAnswers > 0 ? student.correct.value / totalAnswers : 0.0; + + return _buildStudentCard( + name: student.name, + totalBenar: student.correct.value, + totalSalah: student.wrong.value, + progressPercent: progressPercent, + ); + }, + ), + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildSectionHeader(String title) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: Text(title, style: AppTextStyles.title), + ); + } + + Widget _buildCurrentQuestion({required String questionText}) { + return Card( + elevation: 2, + shadowColor: AppColors.shadowPrimary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: AppColors.accentBlue, width: 1), + ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Obx( - () => _buildCurrentQuestion(questionText: controller.currentQuestion.value), - ), - const SizedBox(height: 24), - const Text( - 'Daftar Peserta:', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - Obx( - () => ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: controller.participan.length, - itemBuilder: (context, index) => _buildUserRow( - name: controller.participan[index].name, - totalBenar: controller.participan[index].correct.value, - totalSalah: controller.participan[index].wrong.value, + Row( + children: [ + Icon( + LucideIcons.activity, + color: AppColors.primaryBlue, + size: 18, ), - ), + const SizedBox(width: 8), + Text( + "PERTANYAAN AKTIF", + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: AppColors.primaryBlue, + letterSpacing: 0.8, + ), + ), + ], + ), + Divider(color: AppColors.borderLight, height: 20), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + LucideIcons.helpCircle, + color: AppColors.darkText, + size: 22, + ), + const SizedBox(width: 12), + Expanded( + child: Text( + questionText, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColors.darkText, + ), + ), + ), + ], ), ], ), @@ -42,46 +128,149 @@ class MonitorQuizView extends GetView { ); } - Widget _buildCurrentQuestion({required String questionText}) { - return Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - border: Border.all(color: Colors.blue), - borderRadius: BorderRadius.circular(12), + Widget _buildStudentCard({ + required String name, + required int totalBenar, + required int totalSalah, + required double progressPercent, + }) { + final int totalJawaban = totalBenar + totalSalah; + + return Card( + elevation: 2, + color: Colors.white, + shadowColor: AppColors.shadowPrimary.withOpacity(0.2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: BorderSide(color: AppColors.accentBlue.withOpacity(0.2)), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "pertanyaan sekarang", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.blue, - ), - ), - SizedBox( - height: 10, - ), - Row( - children: [ - const Icon( - LucideIcons.helpCircle, - color: Colors.blue, - size: 24, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - questionText, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.blue, + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + CircleAvatar( + radius: 28, + backgroundColor: AppColors.accentBlue, + child: Text( + name.isNotEmpty ? name[0].toUpperCase() : "?", + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: AppColors.primaryBlue, + ), ), ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + name, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w700, + color: AppColors.darkText, + ), + ), + const SizedBox(height: 4), + Text( + 'Total Jawaban: $totalJawaban', + style: TextStyle( + fontSize: 14, + color: AppColors.softGrayText, + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 20), + LinearPercentIndicator( + animation: true, + animationDuration: 600, + lineHeight: 12.0, + percent: progressPercent, + center: Text( + "${(progressPercent * 100).toInt()}%", + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + barRadius: const Radius.circular(8), + progressColor: _getProgressColor(progressPercent), + backgroundColor: AppColors.disabledBackground, + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: _buildStatCard( + icon: LucideIcons.checkCircle, + color: const Color(0xFF36B37E), + label: "Benar", + value: totalBenar, + ), + ), + const SizedBox(width: 12), + Expanded( + child: _buildStatCard( + icon: LucideIcons.xCircle, + color: const Color(0xFFFF5630), + label: "Salah", + value: totalSalah, + ), + ), + ], + ), + ], + ), + ), + ); + } + + Widget _buildStatCard({ + required IconData icon, + required Color color, + required String label, + required int value, + }) { + return Container( + width: 130, + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), + decoration: BoxDecoration( + color: color.withOpacity(0.08), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: color.withOpacity(0.2), width: 1), + ), + child: Row( + children: [ + Icon(icon, color: color, size: 20), + const SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 12, + color: AppColors.softGrayText, + ), + ), + Text( + value.toString(), + style: TextStyle( + fontSize: 18, + color: color, + fontWeight: FontWeight.bold, + ), ), ], ), @@ -90,75 +279,9 @@ class MonitorQuizView extends GetView { ); } - Widget _buildUserRow({ - required String name, - required int totalBenar, - required int totalSalah, - }) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.grey.shade300, - ), - child: const Icon( - Icons.person, - size: 30, - color: Colors.white, - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - LucideIcons.checkCircle, - color: Colors.green, - size: 18, - ), - const SizedBox(width: 4), - Text( - 'Benar: $totalBenar', - style: const TextStyle(color: Colors.green), - ), - const SizedBox(width: 16), - const Icon( - LucideIcons.xCircle, - color: Colors.red, - size: 18, - ), - const SizedBox(width: 4), - Text( - 'Salah: $totalSalah', - style: const TextStyle(color: Colors.red), - ), - ], - ), - ], - ), - ), - ], - ), - ); + Color _getProgressColor(double percent) { + if (percent < 0.4) return const Color(0xFFFF5630); // Red + if (percent < 0.7) return const Color(0xFFFF991F); // Orange + return const Color(0xFF36B37E); // Green } } diff --git a/lib/feature/play_quiz_multiplayer/view/play_quiz_multiplayer.dart b/lib/feature/play_quiz_multiplayer/view/play_quiz_multiplayer.dart index 55292a6..9368abb 100644 --- a/lib/feature/play_quiz_multiplayer/view/play_quiz_multiplayer.dart +++ b/lib/feature/play_quiz_multiplayer/view/play_quiz_multiplayer.dart @@ -9,7 +9,6 @@ class PlayQuizMultiplayerView extends GetView { Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF9FAFB), - // Remove the AppBar and put everything in the body body: Obx(() { if (controller.isDone.value) { return _buildDoneView(); @@ -19,9 +18,6 @@ class PlayQuizMultiplayerView extends GetView { return const Center(child: CircularProgressIndicator()); } - if (controller.isASentAns.value) { - return const Center(child: Text("you already answer, please wait until the duration is done")); - } return _buildQuestionView(); }), ); @@ -36,30 +32,16 @@ class PlayQuizMultiplayerView extends GetView { // Custom AppBar content moved to body Padding( padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // Back button - IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Get.back(), - ), - // Title - Text( - "Soal ${(question.questionIndex + 1)}/10", - style: const TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - // Empty container for spacing - Container(width: 48), - ], + child: Text( + "Soal ${(question.questionIndex)}/10", + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 24, + ), ), ), - // Timer progress bar Obx(() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), @@ -105,34 +87,69 @@ class PlayQuizMultiplayerView extends GetView { }), const SizedBox(height: 20), + Obx(() { + if (controller.isASentAns.value) { + return Container( + padding: const EdgeInsets.all(20), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Add a nice loading animation - // Question content - Expanded( - child: Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - question.question, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black), + const SizedBox(height: 24), + // Improved text with better styling + const Text( + "Jawaban Anda telah terkirim", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.blue, + ), + ), + const SizedBox(height: 8), + // Informative subtext + const Text( + "Mohon tunggu soal selanjutnya", + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + ], ), - const SizedBox(height: 20), - if (question.type == 'option') _buildOptionQuestion(), - if (question.type == 'fill_the_blank') _buildFillInBlankQuestion(), - if (question.type == 'true_false') _buildTrueFalseQuestion(), - const Spacer(), - Obx( - () => GlobalButton( - text: "Kirim jawaban", - onPressed: controller.submitAnswer, - type: controller.buttonType.value, + ), + ); + } + + return Expanded( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + question.question, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black), ), - ) - ], + const SizedBox(height: 20), + if (question.type == 'option') _buildOptionQuestion(), + if (question.type == 'fill_the_blank') _buildFillInBlankQuestion(), + if (question.type == 'true_false') _buildTrueFalseQuestion(), + const Spacer(), + Obx( + () => GlobalButton( + text: "Kirim jawaban", + onPressed: controller.submitAnswer, + type: controller.buttonType.value, + ), + ) + ], + ), ), - ), - ), + ); + }), + // Question content ], ), ); diff --git a/pubspec.lock b/pubspec.lock index f409f2b..6045306 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -477,6 +477,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + sha256: "157d29133bbc6ecb11f923d36e7960a96a3f28837549a20b65e5135729f0f9fd" + url: "https://pub.dev" + source: hosted + version: "4.2.5" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c5c13c3..0c07a01 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,6 +44,7 @@ dependencies: google_fonts: ^6.1.0 socket_io_client: ^3.1.2 easy_localization: ^3.0.7+1 + percent_indicator: ^4.2.5 dev_dependencies: flutter_test: