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(
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:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/data/models/history/participant_history_result.dart';
import 'package:quiz_app/data/services/answer_service.dart';
@ -12,6 +12,7 @@ class ParticipantResultController extends GetxController {
final RxBool isLoading = false.obs;
RxString participantName = "".obs;
bool isAdmin = false;
@override
void onInit() {
@ -24,6 +25,7 @@ class ParticipantResultController extends GetxController {
final args = Get.arguments;
participantName.value = args["username"];
isAdmin = args["is_admin"];
final response = await _answerService.getAnswerSession(args["session_id"], args["user_id"]);
if (response != null) {
@ -44,4 +46,20 @@ class ParticipantResultController extends GetxController {
int getTotalQuestions() {
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
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.background,
appBar: AppBar(
title: const Text('Detail Peserta'),
backgroundColor: Colors.white,
foregroundColor: AppColors.darkText,
elevation: 0,
leading: IconButton(
icon: const Icon(LucideIcons.arrowLeft),
onPressed: () => Get.back(),
),
),
body: Obx(() {
if (controller.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
return PopScope(
canPop: false,
onPopInvokedWithResult: controller.onPop,
child: Scaffold(
backgroundColor: AppColors.background,
body: Obx(() {
if (controller.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
final participant = controller.participantResult.value;
if (participant == null) {
return const Center(child: Text('Data peserta tidak tersedia.'));
}
final participant = controller.participantResult.value;
if (participant == null) {
return const Center(child: Text('Data peserta tidak tersedia.'));
}
return Column(
children: [
_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);
},
),
return SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
color: Colors.white,
child: Row(
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
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("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 PopScope(
canPop: false,
child: Scaffold(
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,
);
},
return _buildStudentCard(
name: student.name,
totalBenar: student.correct.value,
totalSalah: student.wrong.value,
progressPercent: progressPercent,
);
},
),
),
),
),
],
],
),
),
),
),

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/material.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/data/controllers/user_controller.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
void onClose() {
fillInAnswerController.dispose();
_cancelTimer(); // Important: cancel timer when controller is closed
_cancelTimer();
super.onClose();
}
}
@ -140,7 +150,7 @@ class PlayQuizMultiplayerController extends GetxController {
class MultiplayerQuestionModel {
final int questionIndex;
final String question;
final String type; // 'option', 'true_false', 'fill_in_the_blank'
final String type;
final int duration;
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> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF9FAFB),
body: Obx(() {
if (controller.isDone.value) {
return _buildDoneView();
}
return PopScope(
canPop: false,
child: Scaffold(
backgroundColor: const Color(0xFFF9FAFB),
body: Obx(() {
if (controller.isDone.value) {
return _buildDoneView();
}
if (controller.currentQuestion.value == null) {
return const Center(child: CircularProgressIndicator());
}
if (controller.currentQuestion.value == null) {
return const Center(child: CircularProgressIndicator());
}
return _buildQuestionView();
}),
return _buildQuestionView();
}),
),
);
}
@ -245,10 +248,7 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
// Arahkan ke halaman hasil atau leaderboard
Get.back();
},
onPressed: controller.goToDetailResult,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,