develop #1

Merged
akhdanre merged 104 commits from develop into main 2025-07-10 12:38:53 +07:00
14 changed files with 114 additions and 89 deletions
Showing only changes of commit d5de5fb712 - Show all commits

View File

@ -1,6 +1,6 @@
class APIEndpoint {
static const String baseUrl = "http://192.168.1.18:5000";
// static const String baseUrl = "http://103.193.178.121:5000";
// static const String baseUrl = "http://192.168.107.43:5000";
static const String baseUrl = "http://103.193.178.121:5000";
static const String api = "$baseUrl/api";
static const String login = "/login";

View File

@ -1,23 +1,24 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class CustomFloatingLoading {
static void showLoadingDialog(BuildContext context) {
showDialog(
context: context,
static const String _dialogId = 'custom_loading';
static void showLoadingDialog() {
Get.dialog(
PopScope(
canPop: false,
child: const Center(child: CircularProgressIndicator()),
),
barrierDismissible: false,
barrierColor: Colors.black.withValues(alpha: 0.3),
builder: (BuildContext context) {
return PopScope(
canPop: false,
child: const Center(
child: CircularProgressIndicator(),
),
);
},
barrierColor: Colors.black.withAlpha(76),
name: _dialogId,
);
}
static void hideLoadingDialog(BuildContext context) {
Navigator.of(context).pop();
static void hideLoadingDialog() {
if (Get.isOverlaysOpen) {
Get.until((route) => route.settings.name != _dialogId);
}
}
}

View File

@ -42,7 +42,7 @@ class ConnectionService extends GetxService {
isConnected.value = results.any((result) => result != ConnectivityResult.none);
}
Future<bool> checkConnection() async {
Future<bool> isHaveConnection() async {
final result = await _connectivity.checkConnectivity();
return !result.contains(ConnectivityResult.none);
}

View File

@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/services/connection_service.dart';
import 'package:quiz_app/data/services/socket_service.dart';
import 'package:quiz_app/feature/join_room/controller/join_room_controller.dart';
@ -8,6 +9,12 @@ class JoinRoomBinding extends Bindings {
void dependencies() {
Get.put(SocketService());
Get.lazyPut(() => JoinRoomController(Get.find<SocketService>(), Get.find<UserController>()));
Get.lazyPut(
() => JoinRoomController(
Get.find<SocketService>(),
Get.find<UserController>(),
Get.find<ConnectionService>(),
),
);
}
}

View File

@ -1,23 +1,35 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/core/helper/connection_check.dart';
import 'package:quiz_app/core/utils/custom_floating_loading.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/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/services/connection_service.dart';
import 'package:quiz_app/data/services/socket_service.dart';
class JoinRoomController extends GetxController {
final SocketService _socketService;
final UserController _userController;
final ConnectionService _connectionService;
JoinRoomController(this._socketService, this._userController);
JoinRoomController(
this._socketService,
this._userController,
this._connectionService,
);
final TextEditingController codeController = TextEditingController();
void joinRoom() {
void joinRoom(BuildContext context) {
if (!_connectionService.isCurrentlyConnected) {
ConnectionNotification.noInternedConnection();
return;
}
final code = codeController.text.trim();
if (code.isEmpty) {
@ -29,18 +41,13 @@ class JoinRoomController extends GetxController {
);
return;
}
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
_socketService.initSocketConnection();
_socketService.joinRoom(sessionCode: code, userId: _userController.userData!.id);
_socketService.errors.listen((error) {
Get.snackbar(
"not found",
"Ruangan tidak ditemukan",
backgroundColor: Get.theme.colorScheme.error.withValues(alpha: 0.9),
colorText: Colors.white,
);
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomNotification.error(title: "not found", message: "Ruangan tidak ditemukan");
CustomFloatingLoading.hideLoadingDialog();
});
_socketService.roomMessages.listen((data) {
@ -49,7 +56,7 @@ class JoinRoomController extends GetxController {
final Map<String, dynamic> sessionInfoJson = dataPayload["session_info"];
final Map<String, dynamic> quizInfoJson = dataPayload["quiz_info"];
CustomFloatingLoading.hideLoadingDialog(Get.context!);
// CustomFloatingLoading.hideLoadingDialog(context);
Get.toNamed(
AppRoutes.waitRoomPage,
arguments: WaitingRoomDTO(

View File

@ -182,7 +182,7 @@ class JoinRoomView extends GetView<JoinRoomController> {
const SizedBox(height: 30),
GlobalButton(
text: context.tr("join_quiz_now"),
onPressed: controller.joinRoom,
onPressed: () => controller.joinRoom(context),
),
],
),

View File

@ -88,7 +88,7 @@ class LoginController extends GetxController {
}
try {
isLoading.value = true;
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
final LoginResponseModel response = await _authService.loginWithEmail(
LoginRequestModel(email: email, password: password),
@ -99,11 +99,11 @@ class LoginController extends GetxController {
await _userStorageService.saveUser(userEntity);
_userController.setUserFromEntity(userEntity);
_userStorageService.isLogged = true;
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
Get.offAllNamed(AppRoutes.mainPage);
} catch (e, stackTrace) {
logC.e(e, stackTrace: stackTrace);
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
CustomNotification.error(title: "Gagal", message: "Periksa kembali email dan kata sandi Anda");
}
}
@ -114,12 +114,12 @@ class LoginController extends GetxController {
return;
}
try {
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
final user = await _googleAuthService.signIn();
if (user == null) {
Get.snackbar("Kesalahan", "Masuk dengan Google dibatalkan");
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
return;
}
@ -127,7 +127,7 @@ class LoginController extends GetxController {
if (idToken == null || idToken.isEmpty) {
Get.snackbar("Kesalahan", "Tidak menerima ID Token dari Google");
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
return;
}
@ -137,7 +137,7 @@ class LoginController extends GetxController {
await _userStorageService.saveUser(userEntity);
_userController.setUserFromEntity(userEntity);
_userStorageService.isLogged = true;
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
Get.offAllNamed(AppRoutes.mainPage);
} catch (e, stackTrace) {
logC.e("Google Sign-In Error: $e", stackTrace: stackTrace);

View File

@ -61,7 +61,7 @@ class UpdateProfileController extends GetxController {
Future<void> saveProfile() async {
if (!_validateInputs()) return;
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
final isSuccessUpdate = await _userService.updateProfileData(
_userController.userData!.id,
@ -98,7 +98,7 @@ class UpdateProfileController extends GetxController {
Get.back();
CustomNotification.success(title: "Success", message: "Profile updated successfully");
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
}
bool _isValidDateFormat(String date) {

View File

@ -224,7 +224,7 @@ class QuizCreationController extends GetxController {
}
void generateQuiz() async {
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
try {
BaseResponseModel<List<RawQuizModel>> response = await _quizService.createQuizAuto(inputSentenceTC.text);
@ -262,7 +262,7 @@ class QuizCreationController extends GetxController {
} catch (e) {
logC.e("Error while generating quiz: $e");
} finally {
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
isGenerate.value = false;
if (quizData.isNotEmpty && selectedQuizIndex.value == 0) {

View File

@ -92,7 +92,7 @@ class QuizPreviewController extends GetxController {
}
isLoading.value = true;
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
final now = DateTime.now();
final String formattedDate = "${now.day.toString().padLeft(2, '0')}-${now.month.toString().padLeft(2, '0')}-${now.year}";
@ -122,7 +122,7 @@ class QuizPreviewController extends GetxController {
logC.e(e);
} finally {
isLoading.value = false;
// CustomFloatingLoading.hideLoadingDialog(Get.context!);
// CustomFloatingLoading.hideLoadingDialog();
}
}

View File

@ -81,7 +81,7 @@ class RegisterController extends GetxController {
}
try {
CustomFloatingLoading.showLoadingDialog(Get.context!);
CustomFloatingLoading.showLoadingDialog();
await _authService.register(
RegisterRequestModel(
email: email,
@ -93,10 +93,10 @@ class RegisterController extends GetxController {
);
Get.back();
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
CustomNotification.success(title: "Pendaftaran Berhasil", message: "Akun berhasil dibuat");
} catch (e) {
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomFloatingLoading.hideLoadingDialog();
String errorMessage = e.toString().replaceFirst("Exception: ", "");

View File

@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/services/connection_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/socket_service.dart';
@ -16,6 +17,7 @@ class RoomMakerBinding extends Bindings {
Get.find<UserController>(),
Get.find<SocketService>(),
Get.find<QuizService>(),
Get.find<ConnectionService>(),
));
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/core/helper/connection_check.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/models/base/base_model.dart';
@ -9,6 +11,7 @@ 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_response_model.dart';
import 'package:quiz_app/data/services/connection_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/socket_service.dart';
@ -18,12 +21,14 @@ class RoomMakerController extends GetxController {
final UserController _userController;
final SocketService _socketService;
final QuizService _quizService;
final ConnectionService _connectionService;
RoomMakerController(
this._sessionService,
this._userController,
this._socketService,
this._quizService,
this._connectionService,
);
final selectedQuiz = Rxn<QuizListingModel>();
@ -47,6 +52,10 @@ class RoomMakerController extends GetxController {
}
Future<void> loadQuiz({bool reset = false}) async {
if (!await _connectionService.isHaveConnection()) {
ConnectionNotification.noInternedConnection();
return;
}
if (isLoading) return;
isLoading = true;
@ -92,8 +101,13 @@ class RoomMakerController extends GetxController {
}
void onCreateRoom() async {
if (nameTC.text.trim().isEmpty || selectedQuiz.value == null) {
Get.snackbar("Gagal", "Nama room dan kuis harus dipilih.");
if (nameTC.text.trim().isEmpty || maxPlayerTC.text.trim().isEmpty || selectedQuiz.value == null) {
CustomNotification.error(title: "Gagal", message: "Nama room, maksimal pemain dan kuis harus dipilih.");
return;
}
if (!await _connectionService.isHaveConnection()) {
ConnectionNotification.noInternedConnection();
return;
}

View File

@ -588,52 +588,46 @@ class RoomMakerView extends GetView<RoomMakerController> {
}
Widget _buildCreateRoomButton() {
return Obx(() {
final canCreate = controller.selectedQuiz.value != null && controller.nameTC.text.isNotEmpty && controller.maxPlayerTC.text.isNotEmpty;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: MediaQuery.of(Get.context!).size.width - 32,
height: 56,
child: Material(
elevation: canCreate ? 8 : 2,
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: MediaQuery.of(Get.context!).size.width - 32,
height: 56,
child: Material(
elevation: 8,
borderRadius: BorderRadius.circular(16),
child: InkWell(
borderRadius: BorderRadius.circular(16),
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: canCreate ? controller.onCreateRoom : null,
child: Container(
decoration: BoxDecoration(
gradient: canCreate
? LinearGradient(
colors: [AppColors.primaryBlue, AppColors.primaryBlue.withValues(alpha: 0.8)],
)
: null,
color: !canCreate ? Colors.grey[300] : null,
borderRadius: BorderRadius.circular(16),
onTap: controller.onCreateRoom,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColors.primaryBlue, AppColors.primaryBlue.withValues(alpha: 0.8)],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.add_circle,
color: canCreate ? Colors.white : Colors.grey[500],
size: 24,
color: Colors.grey[300],
borderRadius: BorderRadius.circular(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.add_circle,
color: Colors.white,
size: 24,
),
const SizedBox(width: 12),
Text(
"Buat Room Sekarang",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
const SizedBox(width: 12),
Text(
"Buat Room Sekarang",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: canCreate ? Colors.white : Colors.grey[500],
),
),
],
),
),
],
),
),
),
);
});
),
);
}
}