feat: adding admin result page

This commit is contained in:
akhdanre 2025-05-18 02:30:54 +07:00
parent 82f4a1ec41
commit 737f0f775a
10 changed files with 840 additions and 179 deletions

View File

@ -16,7 +16,7 @@ class MyApp extends StatelessWidget {
localizationsDelegates: context.localizationDelegates, localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales, supportedLocales: context.supportedLocales,
initialBinding: InitialBindings(), initialBinding: InitialBindings(),
initialRoute: AppRoutes.splashScreen, initialRoute: AppRoutes.monitorResultMPLPage,
getPages: AppPages.routes, getPages: AppPages.routes,
); );
} }

View File

@ -11,4 +11,9 @@ class AppColors {
static const Color shadowPrimary = Color(0x330052CC); static const Color shadowPrimary = Color(0x330052CC);
static const Color disabledBackground = Color(0xFFE0E0E0); static const Color disabledBackground = Color(0xFFE0E0E0);
static const Color disabledText = Color(0xFF9E9E9E); 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);
} }

View File

@ -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/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/binding/waiting_room_binding.dart';
import 'package:quiz_app/feature/waiting_room/view/waiting_room_view.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'; part 'app_routes.dart';
@ -135,5 +136,9 @@ class AppPages {
page: () => PlayQuizMultiplayerView(), page: () => PlayQuizMultiplayerView(),
binding: PlayQuizMultiplayerBinding(), binding: PlayQuizMultiplayerBinding(),
), ),
GetPage(
name: AppRoutes.monitorResultMPLPage,
page: () => AdminResultPage(),
)
]; ];
} }

View File

@ -24,4 +24,5 @@ abstract class AppRoutes {
static const playQuizMPLPage = "/room/quiz/play"; static const playQuizMPLPage = "/room/quiz/play";
static const monitorQuizMPLPage = "/room/quiz/monitor"; static const monitorQuizMPLPage = "/room/quiz/monitor";
static const monitorResultMPLPage = "/room/quiz/monitor/result";
} }

View File

@ -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;
// }
// }

View File

@ -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;
// }
// }

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:lucide_icons/lucide_icons.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'; import 'package:quiz_app/feature/monitor_quiz/controller/monitor_quiz_controller.dart';
class MonitorQuizView extends GetView<MonitorQuizController> { class MonitorQuizView extends GetView<MonitorQuizController> {
@ -9,32 +12,115 @@ class MonitorQuizView extends GetView<MonitorQuizController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Monitor Quiz')), backgroundColor: AppColors.background,
body: Padding( body: SafeArea(
padding: const EdgeInsets.all(16.0), 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( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Obx( Row(
() => _buildCurrentQuestion(questionText: controller.currentQuestion.value), children: [
), Icon(
const SizedBox(height: 24), LucideIcons.activity,
const Text( color: AppColors.primaryBlue,
'Daftar Peserta:', size: 18,
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,
), ),
), 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<MonitorQuizController> {
); );
} }
Widget _buildCurrentQuestion({required String questionText}) { Widget _buildStudentCard({
return Container( required String name,
width: double.infinity, required int totalBenar,
padding: const EdgeInsets.all(16), required int totalSalah,
decoration: BoxDecoration( required double progressPercent,
color: Colors.blue.shade50, }) {
border: Border.all(color: Colors.blue), final int totalJawaban = totalBenar + totalSalah;
borderRadius: BorderRadius.circular(12),
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( child: Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(20),
children: [ child: Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
"pertanyaan sekarang", children: [
style: const TextStyle( Row(
fontSize: 16, children: [
fontWeight: FontWeight.w600, CircleAvatar(
color: Colors.blue, radius: 28,
), backgroundColor: AppColors.accentBlue,
), child: Text(
SizedBox( name.isNotEmpty ? name[0].toUpperCase() : "?",
height: 10, style: TextStyle(
), fontSize: 22,
Row( fontWeight: FontWeight.bold,
children: [ color: AppColors.primaryBlue,
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,
), ),
), ),
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<MonitorQuizController> {
); );
} }
Widget _buildUserRow({ Color _getProgressColor(double percent) {
required String name, if (percent < 0.4) return const Color(0xFFFF5630); // Red
required int totalBenar, if (percent < 0.7) return const Color(0xFFFF991F); // Orange
required int totalSalah, return const Color(0xFF36B37E); // Green
}) {
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),
),
],
),
],
),
),
],
),
);
} }
} }

View File

@ -9,7 +9,6 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFF9FAFB), backgroundColor: const Color(0xFFF9FAFB),
// Remove the AppBar and put everything in the body
body: Obx(() { body: Obx(() {
if (controller.isDone.value) { if (controller.isDone.value) {
return _buildDoneView(); return _buildDoneView();
@ -19,9 +18,6 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
return const Center(child: CircularProgressIndicator()); 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(); return _buildQuestionView();
}), }),
); );
@ -36,30 +32,16 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
// Custom AppBar content moved to body // Custom AppBar content moved to body
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Row( child: Text(
mainAxisAlignment: MainAxisAlignment.spaceBetween, "Soal ${(question.questionIndex)}/10",
children: [ style: const TextStyle(
// Back button color: Colors.black,
IconButton( fontWeight: FontWeight.bold,
icon: const Icon(Icons.arrow_back), fontSize: 24,
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),
],
), ),
), ),
// Timer progress bar
Obx(() { Obx(() {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0), padding: const EdgeInsets.symmetric(horizontal: 20.0),
@ -105,34 +87,69 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
}), }),
const SizedBox(height: 20), 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 const SizedBox(height: 24),
Expanded( // Improved text with better styling
child: Padding( const Text(
padding: const EdgeInsets.all(20.0), "Jawaban Anda telah terkirim",
child: Column( style: TextStyle(
crossAxisAlignment: CrossAxisAlignment.start, fontSize: 18,
children: [ fontWeight: FontWeight.bold,
Text( color: Colors.blue,
question.question, ),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black), ),
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(), return Expanded(
Obx( child: Padding(
() => GlobalButton( padding: const EdgeInsets.all(20.0),
text: "Kirim jawaban", child: Column(
onPressed: controller.submitAnswer, crossAxisAlignment: CrossAxisAlignment.start,
type: controller.buttonType.value, 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
], ],
), ),
); );

View File

@ -477,6 +477,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" 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: platform:
dependency: transitive dependency: transitive
description: description:

View File

@ -44,6 +44,7 @@ dependencies:
google_fonts: ^6.1.0 google_fonts: ^6.1.0
socket_io_client: ^3.1.2 socket_io_client: ^3.1.2
easy_localization: ^3.0.7+1 easy_localization: ^3.0.7+1
percent_indicator: ^4.2.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: