feat: adding leave page in the waiting room
This commit is contained in:
parent
da6597f42b
commit
5f54ca6c8c
|
@ -11,7 +11,7 @@ class MyApp extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
title: 'Quiz App',
|
title: 'Quiz App',
|
||||||
locale: Get.locale ?? context.locale, // 🔁 This ensures GetX reacts to locale changes
|
locale: Get.locale ?? context.locale,
|
||||||
fallbackLocale: const Locale('en', 'US'),
|
fallbackLocale: const Locale('en', 'US'),
|
||||||
localizationsDelegates: context.localizationDelegates,
|
localizationsDelegates: context.localizationDelegates,
|
||||||
supportedLocales: context.supportedLocales,
|
supportedLocales: context.supportedLocales,
|
||||||
|
|
|
@ -6,11 +6,13 @@ class GlobalButton extends StatelessWidget {
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
final String text;
|
final String text;
|
||||||
final ButtonType type;
|
final ButtonType type;
|
||||||
|
final Color baseColor;
|
||||||
|
|
||||||
const GlobalButton({
|
const GlobalButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.text,
|
required this.text,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
|
this.baseColor = const Color(0xFF0052CC),
|
||||||
this.type = ButtonType.primary,
|
this.type = ButtonType.primary,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,12 +26,12 @@ class GlobalButton extends StatelessWidget {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ButtonType.primary:
|
case ButtonType.primary:
|
||||||
backgroundColor = const Color(0xFF0052CC);
|
backgroundColor = baseColor;
|
||||||
foregroundColor = Colors.white;
|
foregroundColor = Colors.white;
|
||||||
break;
|
break;
|
||||||
case ButtonType.secondary:
|
case ButtonType.secondary:
|
||||||
backgroundColor = Colors.white;
|
backgroundColor = Colors.white;
|
||||||
foregroundColor = const Color(0xFF0052CC);
|
foregroundColor = baseColor;
|
||||||
borderColor = const Color(0xFF0052CC);
|
borderColor = const Color(0xFF0052CC);
|
||||||
break;
|
break;
|
||||||
case ButtonType.disabled:
|
case ButtonType.disabled:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class GlobalTextField extends StatelessWidget {
|
class GlobalTextField extends StatelessWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
@ -10,6 +9,7 @@ class GlobalTextField extends StatelessWidget {
|
||||||
final bool obscureText;
|
final bool obscureText;
|
||||||
final VoidCallback? onToggleVisibility;
|
final VoidCallback? onToggleVisibility;
|
||||||
final TextInputType textInputType;
|
final TextInputType textInputType;
|
||||||
|
final bool forceUpperCase;
|
||||||
|
|
||||||
const GlobalTextField(
|
const GlobalTextField(
|
||||||
{super.key,
|
{super.key,
|
||||||
|
@ -20,6 +20,7 @@ class GlobalTextField extends StatelessWidget {
|
||||||
this.isPassword = false,
|
this.isPassword = false,
|
||||||
this.obscureText = false,
|
this.obscureText = false,
|
||||||
this.onToggleVisibility,
|
this.onToggleVisibility,
|
||||||
|
this.forceUpperCase = false,
|
||||||
this.textInputType = TextInputType.text});
|
this.textInputType = TextInputType.text});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -28,7 +29,8 @@ class GlobalTextField extends StatelessWidget {
|
||||||
controller: controller,
|
controller: controller,
|
||||||
keyboardType: textInputType,
|
keyboardType: textInputType,
|
||||||
obscureText: isPassword ? obscureText : false,
|
obscureText: isPassword ? obscureText : false,
|
||||||
maxLines: limitTextLine, // <-- ini tambahan dari limitTextLine
|
maxLines: limitTextLine,
|
||||||
|
textCapitalization: forceUpperCase ? TextCapitalization.characters : TextCapitalization.none,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: labelText,
|
labelText: labelText,
|
||||||
labelStyle: const TextStyle(
|
labelStyle: const TextStyle(
|
||||||
|
|
|
@ -58,15 +58,21 @@ class SocketService {
|
||||||
}
|
}
|
||||||
|
|
||||||
void joinRoom({required String sessionCode, required String userId}) {
|
void joinRoom({required String sessionCode, required String userId}) {
|
||||||
socket.emit('join_room', {
|
var data = {
|
||||||
'session_code': sessionCode,
|
'session_code': sessionCode,
|
||||||
'user_id': userId,
|
'user_id': userId,
|
||||||
});
|
};
|
||||||
|
print(data);
|
||||||
|
socket.emit(
|
||||||
|
'join_room',
|
||||||
|
data,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void leaveRoom({required String sessionId, String username = "anonymous"}) {
|
void leaveRoom({required String sessionId, required String userId, String username = "anonymous"}) {
|
||||||
socket.emit('leave_room', {
|
socket.emit('leave_room', {
|
||||||
'session_id': sessionId,
|
'session_id': sessionId,
|
||||||
|
'user_id': userId,
|
||||||
'username': username,
|
'username': username,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ class JoinRoomController extends GetxController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_socketService.initSocketConnection();
|
_socketService.initSocketConnection();
|
||||||
|
|
||||||
_socketService.joinRoom(sessionCode: code, userId: _userController.userData!.id);
|
_socketService.joinRoom(sessionCode: code, userId: _userController.userData!.id);
|
||||||
Get.toNamed(AppRoutes.waitRoomPage, arguments: WaitingRoomDTO(false, SessionResponseModel(sessionId: "", sessionCode: code)));
|
Get.toNamed(AppRoutes.waitRoomPage, arguments: WaitingRoomDTO(false, SessionResponseModel(sessionId: "", sessionCode: code)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ class JoinRoomView extends GetView<JoinRoomController> {
|
||||||
controller: controller.codeController,
|
controller: controller.codeController,
|
||||||
hintText: context.tr("room_code_hint"),
|
hintText: context.tr("room_code_hint"),
|
||||||
textInputType: TextInputType.text,
|
textInputType: TextInputType.text,
|
||||||
|
forceUpperCase: true,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
GlobalButton(
|
GlobalButton(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.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';
|
||||||
import 'package:quiz_app/feature/waiting_room/controller/waiting_room_controller.dart';
|
import 'package:quiz_app/feature/waiting_room/controller/waiting_room_controller.dart';
|
||||||
|
|
||||||
|
@ -6,6 +7,9 @@ class WaitingRoomBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
if (!Get.isRegistered<SocketService>()) Get.put(SocketService());
|
if (!Get.isRegistered<SocketService>()) Get.put(SocketService());
|
||||||
Get.lazyPut<WaitingRoomController>(() => WaitingRoomController(Get.find<SocketService>()));
|
Get.lazyPut<WaitingRoomController>(() => WaitingRoomController(
|
||||||
|
Get.find<SocketService>(),
|
||||||
|
Get.find<UserController>(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:quiz_app/app/routes/app_pages.dart';
|
import 'package:quiz_app/app/routes/app_pages.dart';
|
||||||
|
import 'package:quiz_app/core/utils/custom_notification.dart';
|
||||||
|
import 'package:quiz_app/data/controllers/user_controller.dart';
|
||||||
import 'package:quiz_app/data/dto/waiting_room_dto.dart';
|
import 'package:quiz_app/data/dto/waiting_room_dto.dart';
|
||||||
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
|
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
|
||||||
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
||||||
|
@ -10,7 +12,8 @@ import 'package:quiz_app/data/services/socket_service.dart';
|
||||||
|
|
||||||
class WaitingRoomController extends GetxController {
|
class WaitingRoomController extends GetxController {
|
||||||
final SocketService _socketService;
|
final SocketService _socketService;
|
||||||
WaitingRoomController(this._socketService);
|
final UserController _userController;
|
||||||
|
WaitingRoomController(this._socketService, this._userController);
|
||||||
|
|
||||||
final sessionCode = ''.obs;
|
final sessionCode = ''.obs;
|
||||||
final quizMeta = Rx<QuizListingModel?>(null);
|
final quizMeta = Rx<QuizListingModel?>(null);
|
||||||
|
@ -20,6 +23,7 @@ class WaitingRoomController extends GetxController {
|
||||||
final quizQuestions = <Map<String, dynamic>>[].obs;
|
final quizQuestions = <Map<String, dynamic>>[].obs;
|
||||||
final isQuizStarted = false.obs;
|
final isQuizStarted = false.obs;
|
||||||
|
|
||||||
|
SessionResponseModel? roomData;
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
@ -30,10 +34,10 @@ class WaitingRoomController extends GetxController {
|
||||||
void _loadInitialData() {
|
void _loadInitialData() {
|
||||||
final data = Get.arguments as WaitingRoomDTO;
|
final data = Get.arguments as WaitingRoomDTO;
|
||||||
|
|
||||||
SessionResponseModel? roomData = data.data;
|
roomData = data.data;
|
||||||
isAdmin.value = data.isAdmin;
|
isAdmin.value = data.isAdmin;
|
||||||
|
|
||||||
sessionCode.value = roomData.sessionCode;
|
sessionCode.value = roomData!.sessionCode;
|
||||||
|
|
||||||
quizMeta.value = QuizListingModel(
|
quizMeta.value = QuizListingModel(
|
||||||
quizId: "q123",
|
quizId: "q123",
|
||||||
|
@ -49,9 +53,18 @@ class WaitingRoomController extends GetxController {
|
||||||
|
|
||||||
void _registerSocketListeners() {
|
void _registerSocketListeners() {
|
||||||
_socketService.roomMessages.listen((data) {
|
_socketService.roomMessages.listen((data) {
|
||||||
|
if (data["type"] == "join") {
|
||||||
final user = data["data"];
|
final user = data["data"];
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
joinedUsers.assign(UserModel(id: user['user_id'], name: user['username']));
|
joinedUsers.assign(UserModel(id: user['user_id'], name: user['username']));
|
||||||
|
CustomNotification.success(title: "Participan Joined", message: "${user['username']} has joined to room");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data["type"] == "leave") {
|
||||||
|
final userId = data["data"];
|
||||||
|
CustomNotification.warning(title: "Participan Leave", message: "participan leave the room");
|
||||||
|
joinedUsers.removeWhere((e) => e.id == userId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -86,4 +99,12 @@ class WaitingRoomController extends GetxController {
|
||||||
void startQuiz() {
|
void startQuiz() {
|
||||||
_socketService.startQuiz(sessionCode: sessionCode.value);
|
_socketService.startQuiz(sessionCode: sessionCode.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void leaveRoom() async {
|
||||||
|
_socketService.leaveRoom(sessionId: roomData!.sessionId, userId: _userController.userData!.id);
|
||||||
|
Get.offAllNamed(AppRoutes.mainPage);
|
||||||
|
|
||||||
|
await Future.delayed(Duration(seconds: 2));
|
||||||
|
_socketService.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,13 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
GlobalButton(
|
GlobalButton(
|
||||||
text: "Mulai Kuis",
|
text: "Mulai Kuis",
|
||||||
onPressed: controller.startQuiz,
|
onPressed: controller.startQuiz,
|
||||||
),
|
)
|
||||||
|
else
|
||||||
|
GlobalButton(
|
||||||
|
text: "Tinggalkan Ruangan",
|
||||||
|
onPressed: controller.leaveRoom,
|
||||||
|
baseColor: const Color.fromARGB(255, 204, 14, 0),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
@ -68,6 +74,7 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
if (quiz == null) return const SizedBox.shrink();
|
if (quiz == null) return const SizedBox.shrink();
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColors.background,
|
color: AppColors.background,
|
||||||
border: Border.all(color: AppColors.borderLight),
|
border: Border.all(color: AppColors.borderLight),
|
||||||
|
|
Loading…
Reference in New Issue