From 0283806cf3156e72d396d0433d74d94f61ba7063 Mon Sep 17 00:00:00 2001 From: akhdanre Date: Mon, 26 May 2025 19:05:47 +0700 Subject: [PATCH] fix: waiting room localization and adding room name --- assets/translations/en-US.json | 14 +++- assets/translations/id-ID.json | 14 +++- assets/translations/ms-MY.json | 14 +++- lib/app/const/text/string_extension.dart | 5 ++ .../models/session/session_info_model.dart | 3 + .../models/session/session_request_model.dart | 4 ++ lib/data/services/session_service.dart | 6 +- .../join_room/view/join_room_view.dart | 52 +++++++------- .../controller/room_maker_controller.dart | 1 + .../controller/waiting_room_controller.dart | 2 + .../waiting_room/view/waiting_room_view.dart | 69 ++++++++++++------- 11 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 lib/app/const/text/string_extension.dart diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index 541d554..c0cf4ee 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -138,6 +138,18 @@ }, "get_ready": "Get Ready", - "quiz_starting_soon" : "Quiz Starting Soon" + "quiz_starting_soon": "Quiz Starting Soon", + "waiting_room": { + "title": "Waiting Room", + "participants_joined": "Participants Joined:", + "leave_room": "Leave Room", + "session_code": "Session Code:", + "copy_code": "Copy Code", + "quiz_info": "Quiz Information:", + "quiz_title": "Title", + "quiz_description": "Description", + "quiz_total_question": "Total Questions", + "quiz_duration": "Duration" + } } diff --git a/assets/translations/id-ID.json b/assets/translations/id-ID.json index ccd48c8..8b829f1 100644 --- a/assets/translations/id-ID.json +++ b/assets/translations/id-ID.json @@ -122,5 +122,17 @@ }, "get_ready": "Bersiaplah", - "quiz_starting_soon": "Kuis akan segera dimulai" + "quiz_starting_soon": "Kuis akan segera dimulai", + "waiting_room": { + "title": "Ruang Tunggu", + "participants_joined": "Peserta Bergabung:", + "leave_room": "Keluar dari Ruangan", + "session_code": "Kode Sesi:", + "copy_code": "Salin Kode", + "quiz_info": "Informasi Kuis:", + "quiz_title": "Judul", + "quiz_description": "Deskripsi", + "quiz_total_question": "Total Pertanyaan", + "quiz_duration": "Durasi" + } } diff --git a/assets/translations/ms-MY.json b/assets/translations/ms-MY.json index 0c29ec8..8a4b48c 100644 --- a/assets/translations/ms-MY.json +++ b/assets/translations/ms-MY.json @@ -124,5 +124,17 @@ }, "get_ready": "Bersedia", - "quiz_starting_soon": "Kuiz akan bermula sebentar lagi" + "quiz_starting_soon": "Kuiz akan bermula sebentar lagi", + "waiting_room": { + "title": "Bilik Menunggu", + "participants_joined": "Peserta Telah Sertai:", + "leave_room": "Tinggalkan Bilik", + "session_code": "Kod Sesi:", + "copy_code": "Salin Kod", + "quiz_info": "Maklumat Kuiz:", + "quiz_title": "Tajuk", + "quiz_description": "Penerangan", + "quiz_total_question": "Jumlah Soalan", + "quiz_duration": "Tempoh" + } } diff --git a/lib/app/const/text/string_extension.dart b/lib/app/const/text/string_extension.dart new file mode 100644 index 0000000..060a04f --- /dev/null +++ b/lib/app/const/text/string_extension.dart @@ -0,0 +1,5 @@ +extension StringCasingExtension on String { + String toTitleCase() { + return split(' ').map((word) => word.isNotEmpty ? '${word[0].toUpperCase()}${word.substring(1).toLowerCase()}' : '').join(' '); + } +} diff --git a/lib/data/models/session/session_info_model.dart b/lib/data/models/session/session_info_model.dart index cca5d1d..db7e3de 100644 --- a/lib/data/models/session/session_info_model.dart +++ b/lib/data/models/session/session_info_model.dart @@ -3,6 +3,7 @@ import 'package:quiz_app/data/models/user/user_model.dart'; class SessionInfo { final String id; final String sessionCode; + final String roomName; final String quizId; final String hostId; final DateTime createdAt; @@ -16,6 +17,7 @@ class SessionInfo { SessionInfo({ required this.id, required this.sessionCode, + required this.roomName, required this.quizId, required this.hostId, required this.createdAt, @@ -31,6 +33,7 @@ class SessionInfo { return SessionInfo( id: json['id'], sessionCode: json['session_code'], + roomName: json["room_name"], quizId: json['quiz_id'], hostId: json['host_id'], createdAt: DateTime.parse(json['created_at']), diff --git a/lib/data/models/session/session_request_model.dart b/lib/data/models/session/session_request_model.dart index 6eced2f..2e0dfc8 100644 --- a/lib/data/models/session/session_request_model.dart +++ b/lib/data/models/session/session_request_model.dart @@ -1,11 +1,13 @@ class SessionRequestModel { final String quizId; final String hostId; + final String roomName; final int limitParticipan; SessionRequestModel({ required this.quizId, required this.hostId, + required this.roomName, required this.limitParticipan, }); @@ -13,6 +15,7 @@ class SessionRequestModel { return SessionRequestModel( quizId: json['quiz_id'], hostId: json['host_id'], + roomName: json['room_name'], limitParticipan: json['limit_participan'], ); } @@ -21,6 +24,7 @@ class SessionRequestModel { return { 'quiz_id': quizId, 'host_id': hostId, + 'room_name': roomName, 'limit_participan': limitParticipan, }; } diff --git a/lib/data/services/session_service.dart b/lib/data/services/session_service.dart index 5e19015..0759009 100644 --- a/lib/data/services/session_service.dart +++ b/lib/data/services/session_service.dart @@ -17,11 +17,7 @@ class SessionService extends GetxService { Future?> createSession(SessionRequestModel data) async { try { - final response = await _dio.post(APIEndpoint.session, data: { - 'quiz_id': data.quizId, - 'host_id': data.hostId, - 'limit_participan': data.limitParticipan, - }); + final response = await _dio.post(APIEndpoint.session, data: data.toJson()); if (response.statusCode != 201) { return null; } diff --git a/lib/feature/join_room/view/join_room_view.dart b/lib/feature/join_room/view/join_room_view.dart index 3fa9f69..ffcf3ea 100644 --- a/lib/feature/join_room/view/join_room_view.dart +++ b/lib/feature/join_room/view/join_room_view.dart @@ -33,32 +33,32 @@ class JoinRoomView extends GetView { children: [ const SizedBox(height: 20), - TweenAnimationBuilder( - duration: const Duration(seconds: 1), - tween: Tween(begin: 0.0, end: 1.0), - builder: (context, value, child) { - return Transform.scale( - scale: value, - child: child, - ); - }, - child: Container( - padding: EdgeInsets.all(22), - decoration: BoxDecoration( - color: AppColors.primaryBlue.withValues(alpha: 0.05), - shape: BoxShape.circle, - border: Border.all( - color: AppColors.primaryBlue.withValues(alpha: 0.15), - width: 2, - ), - ), - child: Icon( - LucideIcons.trophy, - size: 70, - color: AppColors.primaryBlue, - ), - ), - ), + // TweenAnimationBuilder( + // duration: const Duration(seconds: 1), + // tween: Tween(begin: 0.0, end: 1.0), + // builder: (context, value, child) { + // return Transform.scale( + // scale: value, + // child: child, + // ); + // }, + // child: Container( + // padding: EdgeInsets.all(22), + // decoration: BoxDecoration( + // color: AppColors.primaryBlue.withValues(alpha: 0.05), + // shape: BoxShape.circle, + // border: Border.all( + // color: AppColors.primaryBlue.withValues(alpha: 0.15), + // width: 2, + // ), + // ), + // child: Icon( + // LucideIcons.trophy, + // size: 70, + // color: AppColors.primaryBlue, + // ), + // ), + // ), const SizedBox(height: 30), diff --git a/lib/feature/room_maker/controller/room_maker_controller.dart b/lib/feature/room_maker/controller/room_maker_controller.dart index 3ace6f1..e0b0fdc 100644 --- a/lib/feature/room_maker/controller/room_maker_controller.dart +++ b/lib/feature/room_maker/controller/room_maker_controller.dart @@ -103,6 +103,7 @@ class RoomMakerController extends GetxController { SessionRequestModel( quizId: quiz.quizId, hostId: _userController.userData!.id, + roomName: nameTC.text, limitParticipan: int.parse(maxPlayerTC.text), ), ); diff --git a/lib/feature/waiting_room/controller/waiting_room_controller.dart b/lib/feature/waiting_room/controller/waiting_room_controller.dart index 2ec10e9..b18ace9 100644 --- a/lib/feature/waiting_room/controller/waiting_room_controller.dart +++ b/lib/feature/waiting_room/controller/waiting_room_controller.dart @@ -16,6 +16,7 @@ class WaitingRoomController extends GetxController { WaitingRoomController(this._socketService, this._userController); final sessionCode = ''.obs; + final roomName = "".obs; String sessionId = ''; final quizMeta = Rx(null); final joinedUsers = [].obs; @@ -42,6 +43,7 @@ class WaitingRoomController extends GetxController { sessionId = roomData!.sessionId; quizMeta.value = data.quizInfo; + roomName.value = data.sessionInfo.roomName; joinedUsers.assignAll(data.sessionInfo.participants); } diff --git a/lib/feature/waiting_room/view/waiting_room_view.dart b/lib/feature/waiting_room/view/waiting_room_view.dart index 860110a..7eaa603 100644 --- a/lib/feature/waiting_room/view/waiting_room_view.dart +++ b/lib/feature/waiting_room/view/waiting_room_view.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:quiz_app/app/const/text/string_extension.dart'; +import 'package:quiz_app/app/const/text/text_style.dart'; import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/data/models/quiz/quiz_info_model.dart'; import 'package:quiz_app/data/models/user/user_model.dart'; @@ -11,7 +14,9 @@ class WaitingRoomView extends GetView { Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, - appBar: AppBar(title: const Text("Waiting Room")), + appBar: AppBar( + title: Text(tr("waiting_room.title"), style: AppTextStyles.title), + ), body: Padding( padding: const EdgeInsets.all(16.0), child: Obx(() { @@ -22,25 +27,39 @@ class WaitingRoomView extends GetView { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + const SizedBox(height: 20), + Center( + child: Obx(() => Text( + controller.roomName.value.toTitleCase(), + style: AppTextStyles.title, + )), + ), + const SizedBox(height: 20), _buildQuizMeta(quiz!), const SizedBox(height: 20), _buildSessionCode(context, session), const SizedBox(height: 20), - const Text("Peserta yang Bergabung:", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + Text( + tr("waiting_room.participants_joined"), + style: AppTextStyles.subtitle.copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: AppColors.darkText, + ), + ), const SizedBox(height: 10), Expanded(child: Obx(() => _buildUserList(users.toList()))), const SizedBox(height: 16), - if (controller.isAdmin.value) - GlobalButton( - text: "Mulai Kuis", - onPressed: controller.startQuiz, - ) - else - GlobalButton( - text: "Tinggalkan Ruangan", - onPressed: controller.leaveRoom, - baseColor: const Color.fromARGB(255, 204, 14, 0), - ) + controller.isAdmin.value + ? GlobalButton( + text: tr("start_quiz"), + onPressed: controller.startQuiz, + ) + : GlobalButton( + text: tr("waiting_room.leave_room"), + onPressed: controller.leaveRoom, + baseColor: const Color.fromARGB(255, 204, 14, 0), + ) ], ); }), @@ -52,18 +71,19 @@ class WaitingRoomView extends GetView { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: AppColors.primaryBlue.withValues(alpha: 0.05), + color: AppColors.accentBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: AppColors.primaryBlue), ), child: Row( children: [ - const Text("Session Code: ", style: TextStyle(fontWeight: FontWeight.bold)), - SelectableText(code, style: const TextStyle(fontSize: 16)), + Text(tr("waiting_room.session_code"), style: AppTextStyles.statValue), + const SizedBox(width: 4), + SelectableText(code, style: AppTextStyles.body.copyWith(fontSize: 16)), const Spacer(), IconButton( icon: const Icon(Icons.copy), - tooltip: 'Salin Kode', + tooltip: tr("waiting_room.copy_code"), onPressed: () => controller.copySessionCode(context), ), ], @@ -72,7 +92,6 @@ class WaitingRoomView extends GetView { } Widget _buildQuizMeta(QuizInfo quiz) { - // if (quiz == null) return const SizedBox.shrink(); return Container( padding: const EdgeInsets.all(16), width: double.infinity, @@ -84,12 +103,12 @@ class WaitingRoomView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text("Informasi Kuis:", style: TextStyle(fontWeight: FontWeight.bold)), + Text(tr("waiting_room.quiz_info"), style: AppTextStyles.subtitle.copyWith(fontWeight: FontWeight.bold)), const SizedBox(height: 8), - Text("Judul: ${quiz.title}"), - Text("Deskripsi: ${quiz.description}"), - Text("Jumlah Soal: ${quiz.totalQuiz}"), - Text("Durasi: ${quiz.limitDuration ~/ 60} menit"), + Text("${tr("waiting_room.quiz_title")}: ${quiz.title}", style: AppTextStyles.body), + Text("${tr("waiting_room.quiz_description")}: ${quiz.description}", style: AppTextStyles.body), + Text("${tr("waiting_room.quiz_total_question")}: ${quiz.totalQuiz}", style: AppTextStyles.body), + Text("${tr("waiting_room.quiz_duration")}: ${quiz.limitDuration ~/ 60} min", style: AppTextStyles.body), ], ), ); @@ -110,9 +129,9 @@ class WaitingRoomView extends GetView { ), child: Row( children: [ - CircleAvatar(child: Text(user.username[0])), + CircleAvatar(child: Text(user.username[0].toUpperCase())), const SizedBox(width: 12), - Text(user.username, style: const TextStyle(fontSize: 16)), + Text(user.username, style: AppTextStyles.body.copyWith(fontSize: 16)), ], ), );