fix: adjustment on the notification and loading
This commit is contained in:
parent
048410786b
commit
e3d2cbb7a6
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()}");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue