From ae49bb34d098cbd156229cfeba723bb6f66489db Mon Sep 17 00:00:00 2001 From: akhdanre Date: Thu, 5 Jun 2025 20:35:35 +0700 Subject: [PATCH] fix: adding loading and connection limitation --- lib/core/endpoint/api_endpoint.dart | 4 +- lib/core/utils/custom_floating_loading.dart | 34 +++-- .../binding/detail_quiz_binding.dart | 8 +- .../controller/detail_quiz_controller.dart | 20 ++- .../detail_quiz/view/detail_quix_view.dart | 126 +++++++++--------- .../history/binding/history_binding.dart | 9 +- .../controller/history_controller.dart | 18 ++- lib/feature/home/binding/home_binding.dart | 4 + .../home/controller/home_controller.dart | 13 +- .../home/view/component/user_gretings.dart | 1 + .../controller/join_room_controller.dart | 6 +- .../library/binding/library_binding.dart | 7 +- .../controller/library_controller.dart | 21 ++- .../login/controllers/login_controller.dart | 24 ++-- .../bindings/navigation_binding.dart | 3 +- .../controllers/navigation_controller.dart | 18 +++ .../profile/binding/profile_binding.dart | 2 + .../binding/update_profile_binding.dart | 2 + .../controller/profile_controller.dart | 6 + .../controller/update_profile_controller.dart | 98 ++++++++------ .../binding/quiz_creation_binding.dart | 2 + .../controller/quiz_creation_controller.dart | 23 +++- .../binding/quiz_preview_binding.dart | 2 + .../controller/quiz_preview_controller.dart | 11 +- .../controller/register_controller.dart | 6 +- 25 files changed, 317 insertions(+), 151 deletions(-) diff --git a/lib/core/endpoint/api_endpoint.dart b/lib/core/endpoint/api_endpoint.dart index 2cbebcd..9cfcf74 100644 --- a/lib/core/endpoint/api_endpoint.dart +++ b/lib/core/endpoint/api_endpoint.dart @@ -1,6 +1,6 @@ class APIEndpoint { - // static const String baseUrl = "http://192.168.107.43:5000"; - static const String baseUrl = "http://103.193.178.121:5000"; + static const String baseUrl = "http://192.168.1.13:5000"; + // static const String baseUrl = "http://103.193.178.121:5000"; static const String api = "$baseUrl/api"; static const String login = "/login"; diff --git a/lib/core/utils/custom_floating_loading.dart b/lib/core/utils/custom_floating_loading.dart index 6b1a581..6ea9a5d 100644 --- a/lib/core/utils/custom_floating_loading.dart +++ b/lib/core/utils/custom_floating_loading.dart @@ -1,24 +1,32 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; class CustomFloatingLoading { - static const String _dialogId = 'custom_loading'; + static OverlayEntry? _overlayEntry; - static void showLoadingDialog() { - Get.dialog( - PopScope( - canPop: false, - child: const Center(child: CircularProgressIndicator()), + static void showLoading(BuildContext context) { + if (_overlayEntry != null) return; + + _overlayEntry = OverlayEntry( + builder: (_) => Stack( + children: [ + ModalBarrier( + dismissible: false, + color: Colors.black.withValues(alpha: 0.5), + ), + const Center( + child: CircularProgressIndicator(), + ), + ], ), - barrierDismissible: false, - barrierColor: Colors.black.withAlpha(76), - name: _dialogId, ); + + Overlay.of(context).insert(_overlayEntry!); } - static void hideLoadingDialog() { - if (Get.isOverlaysOpen) { - Get.until((route) => route.settings.name != _dialogId); + static void hideLoading() { + if (_overlayEntry?.mounted == true) { + _overlayEntry?.remove(); } + _overlayEntry = null; } } diff --git a/lib/feature/detail_quiz/binding/detail_quiz_binding.dart b/lib/feature/detail_quiz/binding/detail_quiz_binding.dart index 500837a..30d0af5 100644 --- a/lib/feature/detail_quiz/binding/detail_quiz_binding.dart +++ b/lib/feature/detail_quiz/binding/detail_quiz_binding.dart @@ -1,4 +1,5 @@ import 'package:get/get.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/quiz_service.dart'; import 'package:quiz_app/feature/detail_quiz/controller/detail_quiz_controller.dart'; @@ -8,6 +9,11 @@ class DetailQuizBinding extends Bindings { if (!Get.isRegistered()) { Get.lazyPut(() => QuizService()); } - Get.lazyPut(() => DetailQuizController(Get.find())); + Get.lazyPut( + () => DetailQuizController( + Get.find(), + Get.find(), + ), + ); } } diff --git a/lib/feature/detail_quiz/controller/detail_quiz_controller.dart b/lib/feature/detail_quiz/controller/detail_quiz_controller.dart index e089de2..ce2eba8 100644 --- a/lib/feature/detail_quiz/controller/detail_quiz_controller.dart +++ b/lib/feature/detail_quiz/controller/detail_quiz_controller.dart @@ -1,17 +1,20 @@ 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/data/models/base/base_model.dart'; import 'package:quiz_app/data/models/quiz/library_quiz_model.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/quiz_service.dart'; class DetailQuizController extends GetxController { final QuizService _quizService; + final ConnectionService _connectionService; - DetailQuizController(this._quizService); + DetailQuizController(this._quizService, this._connectionService); RxBool isLoading = true.obs; - late QuizData data; + QuizData? data; @override void onInit() { @@ -21,6 +24,11 @@ class DetailQuizController extends GetxController { void loadData() async { final quizId = Get.arguments as String; + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + isLoading.value = false; + return; + } getQuizData(quizId); } @@ -32,5 +40,11 @@ class DetailQuizController extends GetxController { isLoading.value = false; } - void goToPlayPage() => Get.toNamed(AppRoutes.playQuizPage, arguments: data); + void goToPlayPage() { + if (!_connectionService.isCurrentlyConnected) { + ConnectionNotification.noInternedConnection(); + return; + } + Get.toNamed(AppRoutes.playQuizPage, arguments: data); + } } diff --git a/lib/feature/detail_quiz/view/detail_quix_view.dart b/lib/feature/detail_quiz/view/detail_quix_view.dart index 3c467ea..07cfd98 100644 --- a/lib/feature/detail_quiz/view/detail_quix_view.dart +++ b/lib/feature/detail_quiz/view/detail_quix_view.dart @@ -30,70 +30,76 @@ class DetailQuizView extends GetView { body: SafeArea( child: Padding( padding: const EdgeInsets.all(20), - child: Obx( - () => controller.isLoading.value - ? const Center(child: LoadingWidget()) - : SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header Section - Text( - controller.data.title, - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: AppColors.darkText, - ), - ), - const SizedBox(height: 8), - Text( - controller.data.description ?? "", - style: const TextStyle( - fontSize: 14, - color: AppColors.softGrayText, - ), - ), - const SizedBox(height: 16), - Row( - children: [ - const Icon(Icons.calendar_today_rounded, size: 16, color: AppColors.softGrayText), - const SizedBox(width: 6), - Text( - controller.data.date ?? "", - style: const TextStyle(fontSize: 12, color: AppColors.softGrayText), - ), - const SizedBox(width: 12), - const Icon(Icons.timer_rounded, size: 16, color: AppColors.softGrayText), - const SizedBox(width: 6), - Text( - '${controller.data.limitDuration ~/ 60} ${tr('minutes_suffix')}', - style: const TextStyle(fontSize: 12, color: AppColors.softGrayText), - ), - ], - ), - const SizedBox(height: 20), + child: Obx(() { + if (controller.isLoading.value) { + return const Center(child: LoadingWidget()); + } - GlobalButton(text: tr('start_quiz'), onPressed: controller.goToPlayPage), - const SizedBox(height: 20), + if (controller.data == null) { + return const Center(child: Text("Tidak Ditemukan")); + } - const Divider(thickness: 1.2, color: AppColors.borderLight), - const SizedBox(height: 20), - - // Soal Section - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: controller.data.questionListings.length, - itemBuilder: (context, index) { - final question = controller.data.questionListings[index]; - return _buildQuestionItem(question, index + 1); - }, - ), - ], + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header Section + Text( + controller.data!.title, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: AppColors.darkText, ), ), - ), + const SizedBox(height: 8), + Text( + controller.data!.description ?? "", + style: const TextStyle( + fontSize: 14, + color: AppColors.softGrayText, + ), + ), + const SizedBox(height: 16), + Row( + children: [ + const Icon(Icons.calendar_today_rounded, size: 16, color: AppColors.softGrayText), + const SizedBox(width: 6), + Text( + controller.data!.date ?? "", + style: const TextStyle(fontSize: 12, color: AppColors.softGrayText), + ), + const SizedBox(width: 12), + const Icon(Icons.timer_rounded, size: 16, color: AppColors.softGrayText), + const SizedBox(width: 6), + Text( + '${controller.data!.limitDuration ~/ 60} ${tr('minutes_suffix')}', + style: const TextStyle(fontSize: 12, color: AppColors.softGrayText), + ), + ], + ), + const SizedBox(height: 20), + + GlobalButton(text: tr('start_quiz'), onPressed: controller.goToPlayPage), + const SizedBox(height: 20), + + const Divider(thickness: 1.2, color: AppColors.borderLight), + const SizedBox(height: 20), + + // Soal Section + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: controller.data!.questionListings.length, + itemBuilder: (context, index) { + final question = controller.data!.questionListings[index]; + return _buildQuestionItem(question, index + 1); + }, + ), + ], + ), + ); + }), ), ), ); diff --git a/lib/feature/history/binding/history_binding.dart b/lib/feature/history/binding/history_binding.dart index 725ec3c..d6f6b81 100644 --- a/lib/feature/history/binding/history_binding.dart +++ b/lib/feature/history/binding/history_binding.dart @@ -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/history_service.dart'; import 'package:quiz_app/feature/history/controller/history_controller.dart'; @@ -7,6 +8,12 @@ class HistoryBinding extends Bindings { @override void dependencies() { Get.lazyPut(() => HistoryService()); - Get.lazyPut(() => HistoryController(Get.find(), Get.find())); + Get.lazyPut( + () => HistoryController( + Get.find(), + Get.find(), + Get.find(), + ), + ); } } diff --git a/lib/feature/history/controller/history_controller.dart b/lib/feature/history/controller/history_controller.dart index 9801849..edc7856 100644 --- a/lib/feature/history/controller/history_controller.dart +++ b/lib/feature/history/controller/history_controller.dart @@ -1,14 +1,21 @@ 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/data/controllers/user_controller.dart'; import 'package:quiz_app/data/models/history/quiz_history.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/history_service.dart'; class HistoryController extends GetxController { final HistoryService _historyService; final UserController _userController; + final ConnectionService _connectionService; - HistoryController(this._historyService, this._userController); + HistoryController( + this._historyService, + this._userController, + this._connectionService, + ); RxBool isLoading = true.obs; @@ -17,10 +24,15 @@ class HistoryController extends GetxController { @override void onInit() { super.onInit(); - loadDummyHistory(); + loadHistory(); } - void loadDummyHistory() async { + void loadHistory() async { + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + return; + } + historyList.value = await _historyService.getHistory(_userController.userData!.id) ?? []; isLoading.value = false; } diff --git a/lib/feature/home/binding/home_binding.dart b/lib/feature/home/binding/home_binding.dart index e1b47cc..040e687 100644 --- a/lib/feature/home/binding/home_binding.dart +++ b/lib/feature/home/binding/home_binding.dart @@ -1,4 +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/subject_service.dart'; import 'package:quiz_app/feature/home/controller/home_controller.dart'; @@ -10,8 +12,10 @@ class HomeBinding extends Bindings { Get.lazyPut(() => SubjectService()); Get.lazyPut( () => HomeController( + Get.find(), Get.find(), Get.find(), + Get.find(), ), ); } diff --git a/lib/feature/home/controller/home_controller.dart b/lib/feature/home/controller/home_controller.dart index 17a3359..6f7429d 100644 --- a/lib/feature/home/controller/home_controller.dart +++ b/lib/feature/home/controller/home_controller.dart @@ -1,24 +1,28 @@ import 'package:get/get.dart'; import 'package:quiz_app/app/const/enums/listing_type.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/logger.dart'; import 'package:quiz_app/data/controllers/user_controller.dart'; import 'package:quiz_app/data/models/base/base_model.dart'; import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart'; import 'package:quiz_app/data/models/subject/subject_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/subject_service.dart'; import 'package:quiz_app/feature/navigation/controllers/navigation_controller.dart'; class HomeController extends GetxController { - final UserController _userController = Get.find(); - + final UserController _userController; final QuizService _quizService; final SubjectService _subjectService; + final ConnectionService _connectionService; HomeController( + this._userController, this._quizService, this._subjectService, + this._connectionService, ); RxInt timeStatus = 1.obs; @@ -39,6 +43,10 @@ class HomeController extends GetxController { } void _getRecomendationQuiz() async { + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + return; + } BaseResponseModel? response = await _quizService.recommendationQuiz(userId: _userController.userData!.id); if (response != null) { data.assignAll(response.data as List); @@ -46,6 +54,7 @@ class HomeController extends GetxController { } void loadSubjectData() async { + if (!_connectionService.isCurrentlyConnected) return; try { final response = await _subjectService.getSubject(); subjects.assignAll(response.data!); diff --git a/lib/feature/home/view/component/user_gretings.dart b/lib/feature/home/view/component/user_gretings.dart index 147e58d..a563230 100644 --- a/lib/feature/home/view/component/user_gretings.dart +++ b/lib/feature/home/view/component/user_gretings.dart @@ -5,6 +5,7 @@ class UserGretingsComponent extends StatelessWidget { final String userName; final String? userImage; final int greatingStatus; + const UserGretingsComponent({ super.key, required this.userName, diff --git a/lib/feature/join_room/controller/join_room_controller.dart b/lib/feature/join_room/controller/join_room_controller.dart index 934c32e..e099164 100644 --- a/lib/feature/join_room/controller/join_room_controller.dart +++ b/lib/feature/join_room/controller/join_room_controller.dart @@ -41,13 +41,13 @@ class JoinRoomController extends GetxController { ); return; } - CustomFloatingLoading.showLoadingDialog(); + CustomFloatingLoading.showLoading(Get.overlayContext!); _socketService.initSocketConnection(); _socketService.joinRoom(sessionCode: code, userId: _userController.userData!.id); _socketService.errors.listen((error) { CustomNotification.error(title: "not found", message: "Ruangan tidak ditemukan"); - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); }); _socketService.roomMessages.listen((data) { @@ -56,7 +56,7 @@ class JoinRoomController extends GetxController { final Map sessionInfoJson = dataPayload["session_info"]; final Map quizInfoJson = dataPayload["quiz_info"]; - // CustomFloatingLoading.hideLoadingDialog(context); + // CustomFloatingLoading.showLoading(context); Get.toNamed( AppRoutes.waitRoomPage, arguments: WaitingRoomDTO( diff --git a/lib/feature/library/binding/library_binding.dart b/lib/feature/library/binding/library_binding.dart index 6bdaf97..8446aa5 100644 --- a/lib/feature/library/binding/library_binding.dart +++ b/lib/feature/library/binding/library_binding.dart @@ -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/feature/library/controller/library_controller.dart'; @@ -9,6 +10,10 @@ class LibraryBinding extends Bindings { if (!Get.isRegistered()) { Get.lazyPut(() => QuizService()); } - Get.lazyPut(() => LibraryController(Get.find(), Get.find())); + Get.lazyPut(() => LibraryController( + Get.find(), + Get.find(), + Get.find(), + )); } } diff --git a/lib/feature/library/controller/library_controller.dart b/lib/feature/library/controller/library_controller.dart index 37a5425..35c6962 100644 --- a/lib/feature/library/controller/library_controller.dart +++ b/lib/feature/library/controller/library_controller.dart @@ -1,19 +1,26 @@ 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/data/controllers/user_controller.dart'; import 'package:quiz_app/data/models/base/base_model.dart'; import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/quiz_service.dart'; class LibraryController extends GetxController { + final QuizService _quizService; + final UserController _userController; + final ConnectionService _connectionService; + + LibraryController( + this._quizService, + this._userController, + this._connectionService, + ); + RxList quizs = [].obs; RxBool isLoading = true.obs; RxString emptyMessage = "".obs; - - final QuizService _quizService; - final UserController _userController; - LibraryController(this._quizService, this._userController); - int currentPage = 1; @override @@ -23,6 +30,10 @@ class LibraryController extends GetxController { } void loadUserQuiz() async { + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + return; + } try { isLoading.value = true; BaseResponseModel>? response = await _quizService.userQuiz(_userController.userData!.id, currentPage); diff --git a/lib/feature/login/controllers/login_controller.dart b/lib/feature/login/controllers/login_controller.dart index ba8a8e0..71f66e2 100644 --- a/lib/feature/login/controllers/login_controller.dart +++ b/lib/feature/login/controllers/login_controller.dart @@ -37,13 +37,15 @@ class LoginController extends GetxController { final RxBool isPasswordHidden = true.obs; final RxBool isLoading = false.obs; + late Worker _connectionWorker; + @override void onInit() { super.onInit(); emailController.addListener(validateFields); passwordController.addListener(validateFields); - ever(_connectionService.isConnected, (value) { + _connectionWorker = ever(_connectionService.isConnected, (value) { if (!value) { ConnectionNotification.noInternedConnection(); } else { @@ -88,7 +90,7 @@ class LoginController extends GetxController { } try { isLoading.value = true; - CustomFloatingLoading.showLoadingDialog(); + CustomFloatingLoading.showLoading(Get.overlayContext!); final LoginResponseModel response = await _authService.loginWithEmail( LoginRequestModel(email: email, password: password), @@ -99,11 +101,11 @@ class LoginController extends GetxController { await _userStorageService.saveUser(userEntity); _userController.setUserFromEntity(userEntity); _userStorageService.isLogged = true; - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); Get.offAllNamed(AppRoutes.mainPage); } catch (e, stackTrace) { logC.e(e, stackTrace: stackTrace); - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); CustomNotification.error(title: "Gagal", message: "Periksa kembali email dan kata sandi Anda"); } } @@ -114,12 +116,12 @@ class LoginController extends GetxController { return; } try { - CustomFloatingLoading.showLoadingDialog(); + CustomFloatingLoading.showLoading(Get.overlayContext!); final user = await _googleAuthService.signIn(); if (user == null) { Get.snackbar("Kesalahan", "Masuk dengan Google dibatalkan"); - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); return; } @@ -127,7 +129,7 @@ class LoginController extends GetxController { if (idToken == null || idToken.isEmpty) { Get.snackbar("Kesalahan", "Tidak menerima ID Token dari Google"); - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); return; } @@ -137,7 +139,7 @@ class LoginController extends GetxController { await _userStorageService.saveUser(userEntity); _userController.setUserFromEntity(userEntity); _userStorageService.isLogged = true; - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); Get.offAllNamed(AppRoutes.mainPage); } catch (e, stackTrace) { logC.e("Google Sign-In Error: $e", stackTrace: stackTrace); @@ -160,4 +162,10 @@ class LoginController extends GetxController { phone: response.phone, ); } + + @override + void onClose() { + _connectionWorker.dispose(); + super.onClose(); + } } diff --git a/lib/feature/navigation/bindings/navigation_binding.dart b/lib/feature/navigation/bindings/navigation_binding.dart index a3d6e66..5d39678 100644 --- a/lib/feature/navigation/bindings/navigation_binding.dart +++ b/lib/feature/navigation/bindings/navigation_binding.dart @@ -1,10 +1,11 @@ // feature/navbar/binding/navbar_binding.dart import 'package:get/get.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/feature/navigation/controllers/navigation_controller.dart'; class NavbarBinding extends Bindings { @override void dependencies() { - Get.lazyPut(() => NavigationController()); + Get.lazyPut(() => NavigationController(Get.find())); } } diff --git a/lib/feature/navigation/controllers/navigation_controller.dart b/lib/feature/navigation/controllers/navigation_controller.dart index a281e5f..ffef10a 100644 --- a/lib/feature/navigation/controllers/navigation_controller.dart +++ b/lib/feature/navigation/controllers/navigation_controller.dart @@ -1,8 +1,14 @@ import 'package:get/get.dart'; +import 'package:quiz_app/core/helper/connection_check.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; class NavigationController extends GetxController { RxInt selectedIndex = 0.obs; + final ConnectionService _connectionService; + + NavigationController(this._connectionService); + @override void onInit() { super.onInit(); @@ -12,6 +18,18 @@ class NavigationController extends GetxController { } } + @override + void onReady() { + ever(_connectionService.isConnected, (value) { + if (!value) { + ConnectionNotification.noInternedConnection(); + } else { + ConnectionNotification.internetConnected(); + } + }); + super.onReady(); + } + void changePage(int page) { selectedIndex.value = page; } diff --git a/lib/feature/profile/binding/profile_binding.dart b/lib/feature/profile/binding/profile_binding.dart index 086bfdd..9da327e 100644 --- a/lib/feature/profile/binding/profile_binding.dart +++ b/lib/feature/profile/binding/profile_binding.dart @@ -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/google_auth_service.dart'; import 'package:quiz_app/data/services/user_service.dart'; import 'package:quiz_app/data/services/user_storage_service.dart'; @@ -15,6 +16,7 @@ class ProfileBinding extends Bindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } } diff --git a/lib/feature/profile/binding/update_profile_binding.dart b/lib/feature/profile/binding/update_profile_binding.dart index db18f20..a09dbe9 100644 --- a/lib/feature/profile/binding/update_profile_binding.dart +++ b/lib/feature/profile/binding/update_profile_binding.dart @@ -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/user_service.dart'; import 'package:quiz_app/data/services/user_storage_service.dart'; import 'package:quiz_app/feature/profile/controller/update_profile_controller.dart'; @@ -12,6 +13,7 @@ class UpdateProfileBinding extends Bindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } } diff --git a/lib/feature/profile/controller/profile_controller.dart b/lib/feature/profile/controller/profile_controller.dart index d291820..44da7fe 100644 --- a/lib/feature/profile/controller/profile_controller.dart +++ b/lib/feature/profile/controller/profile_controller.dart @@ -8,6 +8,7 @@ import 'package:quiz_app/core/endpoint/api_endpoint.dart'; import 'package:quiz_app/core/utils/logger.dart'; import 'package:quiz_app/data/controllers/user_controller.dart'; import 'package:quiz_app/data/models/user/user_stat_model.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/google_auth_service.dart'; import 'package:quiz_app/data/services/user_service.dart'; import 'package:quiz_app/data/services/user_storage_service.dart'; @@ -18,12 +19,14 @@ class ProfileController extends GetxController { final UserStorageService _userStorageService; final GoogleAuthService _googleAuthService; final UserService _userService; + final ConnectionService _connectionService; ProfileController( this._userController, this._userStorageService, this._googleAuthService, this._userService, + this._connectionService, ); // User basic info @@ -74,6 +77,9 @@ class ProfileController extends GetxController { } void loadUserStat() async { + if (!await _connectionService.isHaveConnection()) { + return; + } try { final result = await _userService.getUserStat(_userController.userData!.id); if (result != null) { diff --git a/lib/feature/profile/controller/update_profile_controller.dart b/lib/feature/profile/controller/update_profile_controller.dart index 5d283ea..bfbf60f 100644 --- a/lib/feature/profile/controller/update_profile_controller.dart +++ b/lib/feature/profile/controller/update_profile_controller.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:get/get.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/core/utils/logger.dart'; import 'package:quiz_app/data/controllers/user_controller.dart'; import 'package:quiz_app/data/entity/user/user_entity.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/user_service.dart'; import 'package:quiz_app/data/services/user_storage_service.dart'; @@ -11,11 +14,13 @@ class UpdateProfileController extends GetxController { final UserController _userController; final UserStorageService _userStorageService; final UserService _userService; + final ConnectionService _connectionService; UpdateProfileController( this._userService, this._userController, this._userStorageService, + this._connectionService, ); final nameController = TextEditingController(); @@ -44,61 +49,76 @@ class UpdateProfileController extends GetxController { final name = nameController.text.trim(); final phone = phoneController.text.trim(); final birthDate = birthDateController.text.trim(); - print(birthDate); if (name.isEmpty || phone.isEmpty || birthDate.isEmpty) { - Get.snackbar('Validation Error', 'All fields must be filled.', snackPosition: SnackPosition.TOP); + CustomNotification.error( + title: 'Validation Error', + message: 'All fields must be filled.', + ); return false; } if (!_isValidDateFormat(birthDate)) { - Get.snackbar('Validation Error', 'birth date must valid.', snackPosition: SnackPosition.TOP); + CustomNotification.error( + title: 'Validation Error', + message: 'birth date must valid.', + ); return false; } return true; } Future saveProfile() async { - if (!_validateInputs()) return; + if (!await _connectionService.isHaveConnection()) { + // Get.back(); - CustomFloatingLoading.showLoadingDialog(); - - final isSuccessUpdate = await _userService.updateProfileData( - _userController.userData!.id, - nameController.text.trim(), - birthDate: birthDateController.text.trim(), - phone: phoneController.text.trim(), - locale: selectedLocale.value, - ); - - if (isSuccessUpdate) { - final response = await _userService.getUserData(_userController.userData!.id); - - if (response?.data != null) { - final userNew = response!.data!; - final newUser = UserEntity( - id: userNew.id, - email: userNew.email, - name: userNew.name, - birthDate: userNew.birthDate, - locale: userNew.locale, - picUrl: userNew.picUrl, - phone: userNew.phone, - ); - - _userStorageService.saveUser(newUser); - _userController.userData = newUser; - - _userController.email.value = userNew.email; - _userController.userName.value = userNew.name; - _userController.userImage.value = userNew.picUrl; - } + ConnectionNotification.noInternedConnection(); + return; } - Get.back(); + if (!_validateInputs()) return; - CustomNotification.success(title: "Success", message: "Profile updated successfully"); - CustomFloatingLoading.hideLoadingDialog(); + try { + CustomFloatingLoading.showLoading(Get.overlayContext!); + final isSuccessUpdate = await _userService.updateProfileData( + _userController.userData!.id, + nameController.text.trim(), + birthDate: birthDateController.text.trim(), + phone: phoneController.text.trim(), + locale: selectedLocale.value, + ); + + if (isSuccessUpdate) { + final response = await _userService.getUserData(_userController.userData!.id); + + if (response?.data != null) { + final userNew = response!.data!; + final newUser = UserEntity( + id: userNew.id, + email: userNew.email, + name: userNew.name, + birthDate: userNew.birthDate, + locale: userNew.locale, + picUrl: userNew.picUrl, + phone: userNew.phone, + ); + + _userStorageService.saveUser(newUser); + _userController.userData = newUser; + + _userController.email.value = userNew.email; + _userController.userName.value = userNew.name; + _userController.userImage.value = userNew.picUrl; + } + } + CustomFloatingLoading.hideLoading(); + + Get.back(); + CustomNotification.success(title: "Success", message: "Profile updated successfully"); + } catch (e) { + CustomNotification.success(title: "something wrong", message: "failed to update profile"); + logC.e(e); + } } bool _isValidDateFormat(String date) { diff --git a/lib/feature/quiz_creation/binding/quiz_creation_binding.dart b/lib/feature/quiz_creation/binding/quiz_creation_binding.dart index 8fd8031..64de799 100644 --- a/lib/feature/quiz_creation/binding/quiz_creation_binding.dart +++ b/lib/feature/quiz_creation/binding/quiz_creation_binding.dart @@ -1,4 +1,5 @@ import "package:get/get.dart"; +import "package:quiz_app/data/services/connection_service.dart"; import "package:quiz_app/data/services/quiz_service.dart"; import "package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart"; @@ -9,6 +10,7 @@ class QuizCreationBinding extends Bindings { Get.lazyPut( () => QuizCreationController( Get.find(), + Get.find(), ), ); } diff --git a/lib/feature/quiz_creation/controller/quiz_creation_controller.dart b/lib/feature/quiz_creation/controller/quiz_creation_controller.dart index 8886991..cd47fc5 100644 --- a/lib/feature/quiz_creation/controller/quiz_creation_controller.dart +++ b/lib/feature/quiz_creation/controller/quiz_creation_controller.dart @@ -5,16 +5,22 @@ import 'package:quiz_app/app/const/enums/question_type.dart'; import 'package:quiz_app/app/routes/app_pages.dart'; import 'package:quiz_app/component/notification/delete_confirmation.dart'; import 'package:quiz_app/component/notification/pop_up_confirmation.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/core/utils/logger.dart'; import 'package:quiz_app/data/models/base/base_model.dart'; import 'package:quiz_app/data/models/quiz/quiestion_data_model.dart'; +import 'package:quiz_app/data/services/connection_service.dart'; import 'package:quiz_app/data/services/quiz_service.dart'; class QuizCreationController extends GetxController { final QuizService _quizService; - - QuizCreationController(this._quizService); + final ConnectionService _connectionService; + QuizCreationController( + this._quizService, + this._connectionService, + ); final TextEditingController inputSentenceTC = TextEditingController(); final TextEditingController questionTC = TextEditingController(); @@ -224,7 +230,16 @@ class QuizCreationController extends GetxController { } void generateQuiz() async { - CustomFloatingLoading.showLoadingDialog(); + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + return; + } + + if (inputSentenceTC.text.trim().isEmpty) { + CustomNotification.error(title: "Gagal", message: "kalimat atau paragraph tidak boleh kosong"); + return; + } + CustomFloatingLoading.showLoading(Get.overlayContext!); try { BaseResponseModel> response = await _quizService.createQuizAuto(inputSentenceTC.text); @@ -262,7 +277,7 @@ class QuizCreationController extends GetxController { } catch (e) { logC.e("Error while generating quiz: $e"); } finally { - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); isGenerate.value = false; if (quizData.isNotEmpty && selectedQuizIndex.value == 0) { diff --git a/lib/feature/quiz_preview/binding/quiz_preview_binding.dart b/lib/feature/quiz_preview/binding/quiz_preview_binding.dart index efbc228..a5a6d9b 100644 --- a/lib/feature/quiz_preview/binding/quiz_preview_binding.dart +++ b/lib/feature/quiz_preview/binding/quiz_preview_binding.dart @@ -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/subject_service.dart'; import 'package:quiz_app/feature/quiz_preview/controller/quiz_preview_controller.dart'; @@ -13,6 +14,7 @@ class QuizPreviewBinding extends Bindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } } diff --git a/lib/feature/quiz_preview/controller/quiz_preview_controller.dart b/lib/feature/quiz_preview/controller/quiz_preview_controller.dart index a74d267..c13dbfb 100644 --- a/lib/feature/quiz_preview/controller/quiz_preview_controller.dart +++ b/lib/feature/quiz_preview/controller/quiz_preview_controller.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:quiz_app/app/const/enums/question_type.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/core/utils/logger.dart'; @@ -10,6 +11,7 @@ import 'package:quiz_app/data/models/quiz/question_create_request.dart'; import 'package:quiz_app/data/models/quiz/question_listings_model.dart'; import 'package:quiz_app/data/models/quiz/quiestion_data_model.dart'; import 'package:quiz_app/data/models/subject/subject_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/subject_service.dart'; @@ -20,11 +22,13 @@ class QuizPreviewController extends GetxController { final QuizService _quizService; final UserController _userController; final SubjectService _subjectService; + final ConnectionService _connectionService; QuizPreviewController( this._quizService, this._userController, this._subjectService, + this._connectionService, ); RxBool isPublic = false.obs; @@ -70,6 +74,10 @@ class QuizPreviewController extends GetxController { Future onSaveQuiz() async { try { + if (!await _connectionService.isHaveConnection()) { + ConnectionNotification.noInternedConnection(); + return; + } if (isLoading.value) return; final title = titleController.text.trim(); @@ -92,7 +100,7 @@ class QuizPreviewController extends GetxController { } isLoading.value = true; - CustomFloatingLoading.showLoadingDialog(); + CustomFloatingLoading.showLoading(Get.overlayContext!); final now = DateTime.now(); final String formattedDate = "${now.day.toString().padLeft(2, '0')}-${now.month.toString().padLeft(2, '0')}-${now.year}"; @@ -122,7 +130,6 @@ class QuizPreviewController extends GetxController { logC.e(e); } finally { isLoading.value = false; - // CustomFloatingLoading.hideLoadingDialog(); } } diff --git a/lib/feature/register/controller/register_controller.dart b/lib/feature/register/controller/register_controller.dart index 13816d8..09db64a 100644 --- a/lib/feature/register/controller/register_controller.dart +++ b/lib/feature/register/controller/register_controller.dart @@ -81,7 +81,7 @@ class RegisterController extends GetxController { } try { - CustomFloatingLoading.showLoadingDialog(); + CustomFloatingLoading.showLoading(Get.overlayContext!); await _authService.register( RegisterRequestModel( email: email, @@ -93,10 +93,10 @@ class RegisterController extends GetxController { ); Get.back(); - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); CustomNotification.success(title: "Pendaftaran Berhasil", message: "Akun berhasil dibuat"); } catch (e) { - CustomFloatingLoading.hideLoadingDialog(); + CustomFloatingLoading.hideLoading(); String errorMessage = e.toString().replaceFirst("Exception: ", "");