fix: join system
This commit is contained in:
parent
1cce1aba2c
commit
81d900878f
|
@ -1,8 +1,17 @@
|
||||||
|
import 'package:quiz_app/data/models/quiz/quiz_info_model.dart';
|
||||||
|
import 'package:quiz_app/data/models/session/session_info_model.dart';
|
||||||
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
||||||
|
|
||||||
class WaitingRoomDTO {
|
class WaitingRoomDTO {
|
||||||
final bool isAdmin;
|
final bool isAdmin;
|
||||||
final SessionResponseModel data;
|
final SessionResponseModel data;
|
||||||
|
final SessionInfo sessionInfo;
|
||||||
|
final QuizInfo quizInfo;
|
||||||
|
|
||||||
WaitingRoomDTO(this.isAdmin, this.data);
|
WaitingRoomDTO({
|
||||||
|
required this.isAdmin,
|
||||||
|
required this.data,
|
||||||
|
required this.sessionInfo,
|
||||||
|
required this.quizInfo,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
class QuizInfo {
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final int totalQuiz;
|
||||||
|
final int limitDuration;
|
||||||
|
|
||||||
|
QuizInfo({
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
required this.totalQuiz,
|
||||||
|
required this.limitDuration,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory QuizInfo.fromJson(Map<String, dynamic> json) {
|
||||||
|
return QuizInfo(
|
||||||
|
title: json['title'],
|
||||||
|
description: json['description'],
|
||||||
|
totalQuiz: json['total_quiz'],
|
||||||
|
limitDuration: json['limit_duration'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'title': title,
|
||||||
|
'description': description,
|
||||||
|
'question_count': totalQuiz,
|
||||||
|
'limit_duration': limitDuration,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:quiz_app/data/models/user/user_model.dart';
|
||||||
|
|
||||||
|
class SessionInfo {
|
||||||
|
final String id;
|
||||||
|
final String sessionCode;
|
||||||
|
final String quizId;
|
||||||
|
final String hostId;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime? startedAt;
|
||||||
|
final DateTime? endedAt;
|
||||||
|
final bool isActive;
|
||||||
|
final int participantLimit;
|
||||||
|
final List<UserModel> participants;
|
||||||
|
final int currentQuestionIndex;
|
||||||
|
|
||||||
|
SessionInfo({
|
||||||
|
required this.id,
|
||||||
|
required this.sessionCode,
|
||||||
|
required this.quizId,
|
||||||
|
required this.hostId,
|
||||||
|
required this.createdAt,
|
||||||
|
this.startedAt,
|
||||||
|
this.endedAt,
|
||||||
|
required this.isActive,
|
||||||
|
required this.participantLimit,
|
||||||
|
required this.participants,
|
||||||
|
required this.currentQuestionIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory SessionInfo.fromJson(Map<String, dynamic> json) {
|
||||||
|
return SessionInfo(
|
||||||
|
id: json['id'],
|
||||||
|
sessionCode: json['session_code'],
|
||||||
|
quizId: json['quiz_id'],
|
||||||
|
hostId: json['host_id'],
|
||||||
|
createdAt: DateTime.parse(json['created_at']),
|
||||||
|
startedAt: json['started_at'] != null ? DateTime.parse(json['started_at']) : null,
|
||||||
|
endedAt: json['ended_at'] != null ? DateTime.parse(json['ended_at']) : null,
|
||||||
|
isActive: json['is_active'],
|
||||||
|
participantLimit: json['participan_limit'],
|
||||||
|
participants: (json['participants'] as List<dynamic>?)?.map((e) => UserModel.fromJson(e as Map<String, dynamic>)).toList() ?? [],
|
||||||
|
currentQuestionIndex: json['current_question_index'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'session_code': sessionCode,
|
||||||
|
'quiz_id': quizId,
|
||||||
|
'host_id': hostId,
|
||||||
|
'created_at': createdAt.toIso8601String(),
|
||||||
|
'started_at': startedAt?.toIso8601String(),
|
||||||
|
'ended_at': endedAt?.toIso8601String(),
|
||||||
|
'is_active': isActive,
|
||||||
|
'participant_limit': participantLimit,
|
||||||
|
'participants': participants,
|
||||||
|
'current_question_index': currentQuestionIndex,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,22 @@
|
||||||
class UserModel {
|
class UserModel {
|
||||||
final String id;
|
final String id;
|
||||||
final String name;
|
final String username;
|
||||||
|
final String userPic;
|
||||||
|
final DateTime joinedAt;
|
||||||
|
|
||||||
UserModel({
|
UserModel({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.username,
|
||||||
|
required this.userPic,
|
||||||
|
required this.joinedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserModel(
|
||||||
|
id: json['id'],
|
||||||
|
username: json['username'],
|
||||||
|
userPic: json['user_pic'] ?? "",
|
||||||
|
joinedAt: DateTime.parse(json['joined_at']),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
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/app/routes/app_pages.dart';
|
||||||
|
import 'package:quiz_app/core/utils/logger.dart';
|
||||||
import 'package:quiz_app/data/controllers/user_controller.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_info_model.dart';
|
||||||
|
import 'package:quiz_app/data/models/session/session_info_model.dart';
|
||||||
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
||||||
import 'package:quiz_app/data/services/socket_service.dart';
|
import 'package:quiz_app/data/services/socket_service.dart';
|
||||||
|
|
||||||
|
@ -29,7 +32,30 @@ class JoinRoomController extends GetxController {
|
||||||
_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)));
|
_socketService.errors.listen((error) {
|
||||||
|
logC.i(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
_socketService.roomMessages.listen((data) {
|
||||||
|
if (data["type"] == "join") {
|
||||||
|
final Map<String, dynamic> dataPayload = data["data"];
|
||||||
|
final Map<String, dynamic> sessionInfoJson = dataPayload["session_info"];
|
||||||
|
final Map<String, dynamic> quizInfoJson = dataPayload["quiz_info"];
|
||||||
|
|
||||||
|
Get.toNamed(
|
||||||
|
AppRoutes.waitRoomPage,
|
||||||
|
arguments: WaitingRoomDTO(
|
||||||
|
isAdmin: false,
|
||||||
|
data: SessionResponseModel(
|
||||||
|
sessionId: sessionInfoJson["id"],
|
||||||
|
sessionCode: sessionInfoJson["session_code"],
|
||||||
|
),
|
||||||
|
sessionInfo: SessionInfo.fromJson(sessionInfoJson),
|
||||||
|
quizInfo: QuizInfo.fromJson(quizInfoJson),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -31,7 +31,7 @@ class MonitorQuizController extends GetxController {
|
||||||
userList.map(
|
userList.map(
|
||||||
(user) => ParticipantAnswerPoint(
|
(user) => ParticipantAnswerPoint(
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.username,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,8 +4,11 @@ import 'package:quiz_app/app/routes/app_pages.dart';
|
||||||
import 'package:quiz_app/data/controllers/user_controller.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/base/base_model.dart';
|
import 'package:quiz_app/data/models/base/base_model.dart';
|
||||||
|
import 'package:quiz_app/data/models/quiz/quiz_info_model.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_info_model.dart';
|
||||||
import 'package:quiz_app/data/models/session/session_request_model.dart';
|
import 'package:quiz_app/data/models/session/session_request_model.dart';
|
||||||
|
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
||||||
import 'package:quiz_app/data/services/quiz_service.dart';
|
import 'package:quiz_app/data/services/quiz_service.dart';
|
||||||
import 'package:quiz_app/data/services/session_service.dart';
|
import 'package:quiz_app/data/services/session_service.dart';
|
||||||
import 'package:quiz_app/data/services/socket_service.dart';
|
import 'package:quiz_app/data/services/socket_service.dart';
|
||||||
|
@ -66,7 +69,26 @@ class RoomMakerController extends GetxController {
|
||||||
_socketService.initSocketConnection();
|
_socketService.initSocketConnection();
|
||||||
_socketService.joinRoom(sessionCode: response.data!.sessionCode, userId: _userController.userData!.id);
|
_socketService.joinRoom(sessionCode: response.data!.sessionCode, userId: _userController.userData!.id);
|
||||||
|
|
||||||
Get.toNamed(AppRoutes.waitRoomPage, arguments: WaitingRoomDTO(true, response.data!));
|
_socketService.roomMessages.listen((data) {
|
||||||
|
if (data["type"] == "join") {
|
||||||
|
final Map<String, dynamic> dataPayload = data["data"];
|
||||||
|
final Map<String, dynamic> sessionInfoJson = dataPayload["session_info"];
|
||||||
|
final Map<String, dynamic> quizInfoJson = dataPayload["quiz_info"];
|
||||||
|
|
||||||
|
Get.toNamed(
|
||||||
|
AppRoutes.waitRoomPage,
|
||||||
|
arguments: WaitingRoomDTO(
|
||||||
|
isAdmin: true,
|
||||||
|
data: SessionResponseModel(
|
||||||
|
sessionId: sessionInfoJson["id"],
|
||||||
|
sessionCode: sessionInfoJson["session_code"],
|
||||||
|
),
|
||||||
|
sessionInfo: SessionInfo.fromJson(sessionInfoJson),
|
||||||
|
quizInfo: QuizInfo.fromJson(quizInfoJson),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:quiz_app/app/routes/app_pages.dart';
|
||||||
import 'package:quiz_app/core/utils/custom_notification.dart';
|
import 'package:quiz_app/core/utils/custom_notification.dart';
|
||||||
import 'package:quiz_app/data/controllers/user_controller.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_info_model.dart';
|
||||||
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
import 'package:quiz_app/data/models/session/session_response_model.dart';
|
||||||
import 'package:quiz_app/data/models/user/user_model.dart';
|
import 'package:quiz_app/data/models/user/user_model.dart';
|
||||||
import 'package:quiz_app/data/services/socket_service.dart';
|
import 'package:quiz_app/data/services/socket_service.dart';
|
||||||
|
@ -16,7 +16,7 @@ class WaitingRoomController extends GetxController {
|
||||||
WaitingRoomController(this._socketService, this._userController);
|
WaitingRoomController(this._socketService, this._userController);
|
||||||
|
|
||||||
final sessionCode = ''.obs;
|
final sessionCode = ''.obs;
|
||||||
final quizMeta = Rx<QuizListingModel?>(null);
|
final quizMeta = Rx<QuizInfo?>(null);
|
||||||
final joinedUsers = <UserModel>[].obs;
|
final joinedUsers = <UserModel>[].obs;
|
||||||
final isAdmin = true.obs;
|
final isAdmin = true.obs;
|
||||||
|
|
||||||
|
@ -39,32 +39,44 @@ class WaitingRoomController extends GetxController {
|
||||||
|
|
||||||
sessionCode.value = roomData!.sessionCode;
|
sessionCode.value = roomData!.sessionCode;
|
||||||
|
|
||||||
quizMeta.value = QuizListingModel(
|
quizMeta.value = data.quizInfo;
|
||||||
quizId: "q123",
|
|
||||||
authorId: "a123",
|
joinedUsers.assignAll(data.sessionInfo.participants);
|
||||||
authorName: "Admin",
|
|
||||||
title: "Uji Coba Kuis",
|
|
||||||
description: "Kuis untuk testing",
|
|
||||||
date: DateTime.now().toIso8601String(),
|
|
||||||
totalQuiz: 5,
|
|
||||||
duration: 900,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _registerSocketListeners() {
|
void _registerSocketListeners() {
|
||||||
_socketService.roomMessages.listen((data) {
|
_socketService.roomMessages.listen((data) {
|
||||||
if (data["type"] == "join") {
|
if (data["type"] == "participan_join" || data["type"] == "participan_leave") {
|
||||||
final user = data["data"];
|
joinedUsers.clear();
|
||||||
if (user != null) {
|
|
||||||
joinedUsers.assign(UserModel(id: user['user_id'], name: user['username']));
|
final dataPayload = data["data"];
|
||||||
CustomNotification.success(title: "Participan Joined", message: "${user['username']} has joined to room");
|
final participants = dataPayload["participants"] as List<dynamic>?;
|
||||||
|
|
||||||
|
if (participants != null && participants.isNotEmpty) {
|
||||||
|
final users = participants.map((e) => UserModel.fromJson(e as Map<String, dynamic>)).toList();
|
||||||
|
|
||||||
|
joinedUsers.addAll(users);
|
||||||
|
|
||||||
|
if (data["type"] == "participan_join") {
|
||||||
|
CustomNotification.success(
|
||||||
|
title: "Participant Joined",
|
||||||
|
message: data["message"] ?? "A participant has joined the room.",
|
||||||
|
);
|
||||||
|
} else if (data["type"] == "participan_leave") {
|
||||||
|
CustomNotification.warning(
|
||||||
|
title: "Participant Left",
|
||||||
|
message: data["message"] ?? "A participant has left the room.",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["type"] == "leave") {
|
if (data["type"] == "leave") {
|
||||||
final userId = data["data"];
|
CustomNotification.warning(
|
||||||
CustomNotification.warning(title: "Participan Leave", message: "participan leave the room");
|
title: "Participant Leave",
|
||||||
joinedUsers.removeWhere((e) => e.id == userId);
|
message: "Participant left the room",
|
||||||
|
);
|
||||||
|
// joinedUsers.removeWhere((e) => e.id == userId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,7 +113,11 @@ class WaitingRoomController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
void leaveRoom() async {
|
void leaveRoom() async {
|
||||||
_socketService.leaveRoom(sessionId: roomData!.sessionId, userId: _userController.userData!.id);
|
_socketService.leaveRoom(
|
||||||
|
sessionId: roomData!.sessionId,
|
||||||
|
userId: _userController.userData!.id,
|
||||||
|
username: _userController.userName.value,
|
||||||
|
);
|
||||||
Get.offAllNamed(AppRoutes.mainPage);
|
Get.offAllNamed(AppRoutes.mainPage);
|
||||||
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
await Future.delayed(Duration(seconds: 2));
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:quiz_app/component/global_button.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';
|
import 'package:quiz_app/data/models/user/user_model.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';
|
||||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||||
|
@ -21,7 +22,7 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildQuizMeta(quiz),
|
_buildQuizMeta(quiz!),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildSessionCode(context, session),
|
_buildSessionCode(context, session),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
@ -70,8 +71,8 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQuizMeta(dynamic quiz) {
|
Widget _buildQuizMeta(QuizInfo quiz) {
|
||||||
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,
|
width: double.infinity,
|
||||||
|
@ -88,7 +89,7 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
Text("Judul: ${quiz.title}"),
|
Text("Judul: ${quiz.title}"),
|
||||||
Text("Deskripsi: ${quiz.description}"),
|
Text("Deskripsi: ${quiz.description}"),
|
||||||
Text("Jumlah Soal: ${quiz.totalQuiz}"),
|
Text("Jumlah Soal: ${quiz.totalQuiz}"),
|
||||||
Text("Durasi: ${quiz.duration ~/ 60} menit"),
|
Text("Durasi: ${quiz.limitDuration ~/ 60} menit"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -109,9 +110,9 @@ class WaitingRoomView extends GetView<WaitingRoomController> {
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(child: Text(user.name[0])),
|
CircleAvatar(child: Text(user.username[0])),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(user.name, style: const TextStyle(fontSize: 16)),
|
Text(user.username, style: const TextStyle(fontSize: 16)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue