fix: navigation on the quiz multiplayer and the result page

This commit is contained in:
akhdanre 2025-05-19 02:09:30 +07:00
parent abe21031ec
commit 15e4a9295c
6 changed files with 142 additions and 86 deletions

View File

@ -35,6 +35,11 @@ class AdminResultController extends GetxController {
void goToDetailParticipants(String userId, String username) => Get.toNamed( void goToDetailParticipants(String userId, String username) => Get.toNamed(
AppRoutes.quizMPLResultPage, AppRoutes.quizMPLResultPage,
arguments: {"user_id": userId, "session_id": sessionId, "username": username}, arguments: {
"user_id": userId,
"session_id": sessionId,
"username": username,
"is_admin": true,
},
); );
} }

View File

@ -1,5 +1,5 @@
import 'dart:convert';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/data/models/history/participant_history_result.dart'; import 'package:quiz_app/data/models/history/participant_history_result.dart';
import 'package:quiz_app/data/services/answer_service.dart'; import 'package:quiz_app/data/services/answer_service.dart';
@ -12,6 +12,7 @@ class ParticipantResultController extends GetxController {
final RxBool isLoading = false.obs; final RxBool isLoading = false.obs;
RxString participantName = "".obs; RxString participantName = "".obs;
bool isAdmin = false;
@override @override
void onInit() { void onInit() {
@ -24,6 +25,7 @@ class ParticipantResultController extends GetxController {
final args = Get.arguments; final args = Get.arguments;
participantName.value = args["username"]; participantName.value = args["username"];
isAdmin = args["is_admin"];
final response = await _answerService.getAnswerSession(args["session_id"], args["user_id"]); final response = await _answerService.getAnswerSession(args["session_id"], args["user_id"]);
if (response != null) { if (response != null) {
@ -44,4 +46,20 @@ class ParticipantResultController extends GetxController {
int getTotalQuestions() { int getTotalQuestions() {
return participantResult.value?.totalQuestions ?? 0; return participantResult.value?.totalQuestions ?? 0;
} }
void goBackPage() {
if (isAdmin) {
Get.back();
} else {
Get.offAllNamed(AppRoutes.mainPage);
}
}
void onPop(bool isPop, dynamic value) {
if (isAdmin) {
Get.back();
} else {
Get.offAllNamed(AppRoutes.mainPage);
}
}
} }

View File

@ -12,43 +12,63 @@ class ParticipantDetailPage extends GetView<ParticipantResultController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return PopScope(
backgroundColor: AppColors.background, canPop: false,
appBar: AppBar( onPopInvokedWithResult: controller.onPop,
title: const Text('Detail Peserta'), child: Scaffold(
backgroundColor: Colors.white, backgroundColor: AppColors.background,
foregroundColor: AppColors.darkText, body: Obx(() {
elevation: 0, if (controller.isLoading.value) {
leading: IconButton( return const Center(child: CircularProgressIndicator());
icon: const Icon(LucideIcons.arrowLeft), }
onPressed: () => Get.back(),
),
),
body: Obx(() {
if (controller.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
final participant = controller.participantResult.value; final participant = controller.participantResult.value;
if (participant == null) { if (participant == null) {
return const Center(child: Text('Data peserta tidak tersedia.')); return const Center(child: Text('Data peserta tidak tersedia.'));
} }
return Column( return SafeArea(
children: [ child: Column(
_buildParticipantHeader(participant), crossAxisAlignment: CrossAxisAlignment.start,
Expanded( children: [
child: ListView.builder( Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
itemCount: participant.answers.length, color: Colors.white,
itemBuilder: (context, index) { child: Row(
return _buildAnswerCard(participant.answers[index], index + 1); children: [
}, IconButton(
), icon: const Icon(LucideIcons.arrowLeft),
color: AppColors.darkText,
onPressed: controller.goBackPage,
),
const SizedBox(width: 8),
const Text(
'Detail Peserta',
style: TextStyle(
color: AppColors.darkText,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
),
// Body Content
_buildParticipantHeader(participant),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: participant.answers.length,
itemBuilder: (context, index) {
return _buildAnswerCard(participant.answers[index], index + 1);
},
),
),
],
), ),
], );
); }),
}), ),
); );
} }

View File

@ -11,42 +11,45 @@ class MonitorQuizView extends GetView<MonitorQuizController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return PopScope(
backgroundColor: AppColors.background, canPop: false,
body: SafeArea( child: Scaffold(
child: Padding( backgroundColor: AppColors.background,
padding: const EdgeInsets.all(16.0), body: SafeArea(
child: Column( child: Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(16.0),
children: [ child: Column(
_buildSectionHeader("Monitor Admin"), crossAxisAlignment: CrossAxisAlignment.start,
Obx(() => _buildCurrentQuestion( children: [
questionText: controller.currentQuestion.value, _buildSectionHeader("Monitor Admin"),
)), Obx(() => _buildCurrentQuestion(
const SizedBox(height: 24), questionText: controller.currentQuestion.value,
_buildSectionHeader('Daftar Peserta'), )),
const SizedBox(height: 16), const SizedBox(height: 24),
Expanded( _buildSectionHeader('Daftar Peserta'),
child: Obx( const SizedBox(height: 16),
() => ListView.separated( Expanded(
itemCount: controller.participan.length, child: Obx(
separatorBuilder: (context, index) => const SizedBox(height: 12), () => ListView.separated(
itemBuilder: (context, index) { itemCount: controller.participan.length,
final student = controller.participan[index]; separatorBuilder: (context, index) => const SizedBox(height: 12),
final totalAnswers = student.correct.value + student.wrong.value; itemBuilder: (context, index) {
final progressPercent = totalAnswers > 0 ? student.correct.value / totalAnswers : 0.0; 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( return _buildStudentCard(
name: student.name, name: student.name,
totalBenar: student.correct.value, totalBenar: student.correct.value,
totalSalah: student.wrong.value, totalSalah: student.wrong.value,
progressPercent: progressPercent, progressPercent: progressPercent,
); );
}, },
),
), ),
), ),
), ],
], ),
), ),
), ),
), ),

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/component/global_button.dart';
import 'package:quiz_app/data/controllers/user_controller.dart'; import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/services/socket_service.dart'; import 'package:quiz_app/data/services/socket_service.dart';
@ -129,10 +130,19 @@ class PlayQuizMultiplayerController extends GetxController {
} }
} }
void goToDetailResult() {
Get.offAllNamed(AppRoutes.quizMPLResultPage, arguments: {
"user_id": _userController.userData!.id,
"session_id": sessionId,
"username": _userController.userName.value,
"is_admin": false,
});
}
@override @override
void onClose() { void onClose() {
fillInAnswerController.dispose(); fillInAnswerController.dispose();
_cancelTimer(); // Important: cancel timer when controller is closed _cancelTimer();
super.onClose(); super.onClose();
} }
} }
@ -140,7 +150,7 @@ class PlayQuizMultiplayerController extends GetxController {
class MultiplayerQuestionModel { class MultiplayerQuestionModel {
final int questionIndex; final int questionIndex;
final String question; final String question;
final String type; // 'option', 'true_false', 'fill_in_the_blank' final String type;
final int duration; final int duration;
final List<String>? options; final List<String>? options;

View File

@ -7,19 +7,22 @@ import 'package:quiz_app/feature/play_quiz_multiplayer/controller/play_quiz_cont
class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> { class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return PopScope(
backgroundColor: const Color(0xFFF9FAFB), canPop: false,
body: Obx(() { child: Scaffold(
if (controller.isDone.value) { backgroundColor: const Color(0xFFF9FAFB),
return _buildDoneView(); body: Obx(() {
} if (controller.isDone.value) {
return _buildDoneView();
}
if (controller.currentQuestion.value == null) { if (controller.currentQuestion.value == null) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
return _buildQuestionView(); return _buildQuestionView();
}), }),
),
); );
} }
@ -245,10 +248,7 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
), ),
const SizedBox(height: 40), const SizedBox(height: 40),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: controller.goToDetailResult,
// Arahkan ke halaman hasil atau leaderboard
Get.back();
},
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB), backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white, foregroundColor: Colors.white,