fix: adjustment on the notification and loading

This commit is contained in:
akhdanre 2025-05-21 22:29:22 +07:00
parent 048410786b
commit e3d2cbb7a6
8 changed files with 277 additions and 15 deletions

View File

@ -38,6 +38,15 @@ android {
storePassword = "uppercase12"
}
release {
keyAlias = "genso-prod"
keyPassword = "oukenzeumasio"
storeFile = file("my-release-key.jks")
storePassword = "oukenzeumasio"
}
}
buildTypes {
@ -46,6 +55,10 @@ android {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
release {
signingConfig = signingConfigs.release
}
}
}

View File

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

View File

@ -7,17 +7,17 @@ import 'package:quiz_app/data/models/history/participant_history_result.dart';
import 'package:quiz_app/data/providers/dio_client.dart';
class AnswerService extends GetxService {
late final Dio _dio;
late final Dio dio;
@override
void onInit() {
_dio = Get.find<ApiClient>().dio;
dio = Get.find<ApiClient>().dio;
super.onInit();
}
Future<BaseResponseModel?> submitQuizAnswers(Map<String, dynamic> payload) async {
try {
await _dio.post(
await dio.post(
APIEndpoint.quizAnswer,
data: payload,
);
@ -30,7 +30,7 @@ class AnswerService extends GetxService {
Future<BaseResponseModel<ParticipantResult>?> getAnswerSession(String sessionId, String userId) async {
try {
final response = await _dio.post(APIEndpoint.quizAnswerSession, data: {
final response = await dio.post(APIEndpoint.quizAnswerSession, data: {
"session_id": sessionId,
"user_id": userId,
});

View File

@ -9,17 +9,17 @@ import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
import 'package:quiz_app/data/providers/dio_client.dart';
class QuizService extends GetxService {
late final Dio _dio;
late final Dio dio;
@override
void onInit() {
_dio = Get.find<ApiClient>().dio;
dio = Get.find<ApiClient>().dio;
super.onInit();
}
Future<bool> createQuiz(QuizCreateRequestModel request) async {
try {
final response = await _dio.post(
final response = await dio.post(
APIEndpoint.quiz,
data: request.toJson(),
);
@ -37,7 +37,7 @@ class QuizService extends GetxService {
Future<BaseResponseModel<List<RawQuizModel>>> createQuizAuto(String sentence) async {
try {
final response = await _dio.post(
final response = await dio.post(
APIEndpoint.quizGenerate,
data: {"sentence": sentence},
);
@ -63,7 +63,7 @@ class QuizService extends GetxService {
Future<BaseResponseModel<List<QuizListingModel>>?> userQuiz(String userId, int page) async {
try {
final response = await _dio.get("${APIEndpoint.userQuiz}/$userId?page=$page");
final response = await dio.get("${APIEndpoint.userQuiz}/$userId?page=$page");
if (response.statusCode == 200) {
final parsedResponse = BaseResponseModel<List<QuizListingModel>>.fromJson(
response.data,
@ -82,7 +82,7 @@ class QuizService extends GetxService {
Future<BaseResponseModel<List<QuizListingModel>>?> recomendationQuiz({int page = 1, int amount = 3}) async {
try {
final response = await _dio.get("${APIEndpoint.quizRecomendation}?page=$page&limit=$amount");
final response = await dio.get("${APIEndpoint.quizRecomendation}?page=$page&limit=$amount");
if (response.statusCode == 200) {
final parsedResponse = BaseResponseModel<List<QuizListingModel>>.fromJson(
@ -110,7 +110,7 @@ class QuizService extends GetxService {
};
final uri = Uri.parse(APIEndpoint.quizSearch).replace(queryParameters: queryParams);
final response = await _dio.getUri(uri);
final response = await dio.getUri(uri);
if (response.statusCode == 200) {
final parsedResponse = BaseResponseModel<List<QuizListingModel>>.fromJson(
@ -130,7 +130,7 @@ class QuizService extends GetxService {
Future<BaseResponseModel<QuizData>?> getQuizById(String quizId) async {
try {
final response = await _dio.get("${APIEndpoint.quiz}/$quizId");
final response = await dio.get("${APIEndpoint.quiz}/$quizId");
if (response.statusCode == 200) {
final parsedResponse = BaseResponseModel<QuizData>.fromJson(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/component/global_button.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';
@ -74,7 +75,7 @@ class LoginController extends GetxController {
Get.offAllNamed(AppRoutes.mainPage);
} catch (e, stackTrace) {
logC.e(e, stackTrace: stackTrace);
Get.snackbar("Error", "Failed to connect to server");
CustomNotification.error(title: "failed", message: "Check username and password");
} finally {
isLoading.value = false;
}

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.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/models/register/register_request.dart';
import 'package:quiz_app/data/services/auth_service.dart';
@ -59,6 +61,7 @@ class RegisterController extends GetxController {
}
try {
CustomFloatingLoading.showLoadingDialog(Get.context!);
await _authService.register(
RegisterRequestModel(
email: email,
@ -68,7 +71,10 @@ class RegisterController extends GetxController {
phone: phone,
),
);
Get.back();
CustomFloatingLoading.hideLoadingDialog(Get.context!);
CustomNotification.success(title: "register success", message: "created account successfuly");
} catch (e) {
Get.snackbar("Error", "Failed to register: ${e.toString()}");
}

View File

@ -0,0 +1,128 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:dio/dio.dart';
import 'package:quiz_app/core/endpoint/api_endpoint.dart';
import 'package:quiz_app/data/models/base/base_model.dart';
import 'package:quiz_app/data/services/answer_service.dart';
class MockDio extends Mock implements Dio {}
void main() {
late MockDio mockDio;
late AnswerService answerService;
setUp(() {
mockDio = MockDio();
answerService = AnswerService();
answerService.dio = mockDio;
});
group('AnswerService Tests', () {
test('submitQuizAnswers - Success', () async {
final payload = {'question_id': 'q1', 'answer': 'A'};
when(() => mockDio.post(APIEndpoint.quizAnswer, data: payload)).thenAnswer((_) async => Response(
statusCode: 200,
data: {},
requestOptions: RequestOptions(path: APIEndpoint.quizAnswer),
));
final result = await answerService.submitQuizAnswers(payload);
expect(result, isA<BaseResponseModel>());
expect(result?.message, 'success');
verify(() => mockDio.post(APIEndpoint.quizAnswer, data: payload)).called(1);
});
test('submitQuizAnswers - Failure', () async {
final payload = {'question_id': 'q1', 'answer': 'A'};
when(() => mockDio.post(APIEndpoint.quizAnswer, data: payload)).thenThrow(DioException(
requestOptions: RequestOptions(path: APIEndpoint.quizAnswer),
error: 'Network Error',
type: DioExceptionType.connectionError,
));
final result = await answerService.submitQuizAnswers(payload);
expect(result, isNull);
verify(() => mockDio.post(APIEndpoint.quizAnswer, data: payload)).called(1);
});
test('getAnswerSession - Success', () async {
final sessionId = '682a26b3bedac6c20a215452';
final userId = '680f0e63180b5c19b3751d42';
final responseData = {
"message": "Successfully retrieved the answer",
"data": {
"id": "682a26e6bedac6c20a215453",
"session_id": "682a26b3bedac6c20a215452",
"quiz_id": "682a120f18339f4cc31318e4",
"user_id": "680f0e63180b5c19b3751d42",
"answered_at": "2025-05-19 01:28:22",
"answers": [
{
"index": 1,
"question": "Siapakah ketua Wali Songo yang juga dikenal sebagai Sunan Gresik?",
"target_answer": "Maulana Malik Ibrahim",
"duration": 30,
"type": "fill_the_blank",
"options": null,
"answer": "maulana Malik ibrahim",
"is_correct": true,
"time_spent": 8.0
}
],
"total_score": 100,
"total_correct": 1
},
"meta": null
};
when(() => mockDio.post(APIEndpoint.quizAnswerSession, data: {
"session_id": sessionId,
"user_id": userId,
})).thenAnswer((_) async => Response(
statusCode: 200,
data: responseData,
requestOptions: RequestOptions(path: APIEndpoint.quizAnswerSession),
));
final result = await answerService.getAnswerSession(sessionId, userId);
expect(result, isNotNull);
expect(result?.data?.sessionId, sessionId);
expect(result?.data?.userId, userId);
expect(result?.data?.totalScore, 100);
verify(() => mockDio.post(APIEndpoint.quizAnswerSession, data: {
"session_id": sessionId,
"user_id": userId,
})).called(1);
});
test('getAnswerSession - Failure', () async {
final sessionId = '';
final userId = '';
when(() => mockDio.post(APIEndpoint.quizAnswerSession, data: {
"session_id": sessionId,
"user_id": userId,
})).thenThrow(DioException(
requestOptions: RequestOptions(path: APIEndpoint.quizAnswerSession),
error: 'Network Error',
type: DioExceptionType.connectionError,
));
final result = await answerService.getAnswerSession(sessionId, userId);
expect(result, isNull);
verify(() => mockDio.post(APIEndpoint.quizAnswerSession, data: {
"session_id": sessionId,
"user_id": userId,
})).called(1);
});
});
}

View File

@ -0,0 +1,114 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:dio/dio.dart';
import 'package:quiz_app/data/models/quiz/question_listings_model.dart';
import 'package:quiz_app/data/providers/dio_client.dart';
import 'package:quiz_app/data/services/quiz_service.dart';
import 'package:quiz_app/data/models/quiz/question_create_request.dart';
class MockDio extends Mock implements Dio {}
class MockApiClient extends Mock implements ApiClient {}
void main() {
late MockDio mockDio;
late QuizService quizService;
setUp(() {
mockDio = MockDio();
quizService = QuizService();
quizService.dio = mockDio;
});
group('createQuiz', () {
final request = QuizCreateRequestModel(
title: 'Test Quiz',
description: 'A sample quiz description',
isPublic: true,
date: '2025-05-19',
totalQuiz: 1,
limitDuration: 60,
authorId: 'author_123',
subjectId: 'subject_456',
questionListings: [
QuestionListing(
index: 1,
question: 'Sample question?',
targetAnswer: 'Sample Answer',
duration: 30,
type: 'multiple_choice',
)
],
);
test('returns true when status code is 201', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: ''),
statusCode: 201,
),
);
final result = await quizService.createQuiz(request);
expect(result, true);
});
test('throws Exception on non-201 response', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: ''),
statusCode: 400,
),
);
expect(() => quizService.createQuiz(request), throwsException);
});
test('throws Exception on Dio error', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenThrow(Exception('Network Error'));
expect(() => quizService.createQuiz(request), throwsException);
});
});
group('createQuizAuto', () {
const sentence = "This is a test sentence.";
final mockResponseData = {
'message': "succes create quiz automatic",
'data': [
{'qustion': 'What is this?', 'answer': 'A test.'},
]
};
test('returns BaseResponseModel when status code is 200', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: ''),
statusCode: 200,
data: mockResponseData,
),
);
final result = await quizService.createQuizAuto(sentence);
expect(result.data, isA<List<RawQuizModel>>());
expect(result.data!.first.qustion, 'What is this?');
});
test('throws Exception on non-200 response', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: ''),
statusCode: 500,
),
);
expect(() => quizService.createQuizAuto(sentence), throwsException);
});
test('throws Exception on Dio error', () async {
when(() => mockDio.post(any(), data: any(named: 'data'))).thenThrow(Exception('Network Error'));
expect(() => quizService.createQuizAuto(sentence), throwsException);
});
});
}