// import 'dart:async'; // import 'dart:convert'; // import 'dart:io'; // // import 'package:flutter/foundation.dart'; // import 'package:http/http.dart'; // import 'package:http/io_client.dart'; // import 'package:mohem_flutter_app/exceptions/api_exception.dart'; // import 'package:mohem_flutter_app/main.dart'; // import 'package:mohem_flutter_app/models/generic_mapper_model.dart'; // // ignore_for_file: avoid_annotating_with_dynamic // // typedef FactoryConstructor = U Function(dynamic); // // class APIError { // int? errorCode; // int? errorType; // String? errorMessage; // int? errorStatusCode; // // APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode); // // Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode}; // // @override // String toString() { // return jsonEncode(this); // } // } // // APIException _throwAPIException(Response response) { // switch (response.statusCode) { // case 200: // APIError? apiError; // if (response.body != null && response.body.isNotEmpty) { // var jsonError = jsonDecode(response.body); // print(jsonError); // apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']); // } // return APIException(APIException.BAD_REQUEST, error: apiError); // case 400: // APIError? apiError; // if (response.body != null && response.body.isNotEmpty) { // var jsonError = jsonDecode(response.body); // apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']); // } // return APIException(APIException.BAD_REQUEST, error: apiError); // case 401: // return const APIException(APIException.UNAUTHORIZED); // case 403: // return const APIException(APIException.FORBIDDEN); // case 404: // return const APIException(APIException.NOT_FOUND); // case 500: // return const APIException(APIException.INTERNAL_SERVER_ERROR); // case 444: // var downloadUrl = response.headers["location"]; // return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); // default: // return const APIException(APIException.OTHER); // } // } // // class ApiClient { // static final ApiClient _instance = ApiClient._internal(); // // ApiClient._internal(); // // factory ApiClient() => _instance; // // Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, // {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false, bool returnJsonData = true}) async { // var _headers = {'Accept': 'application/json'}; // if (headers != null && headers.isNotEmpty) { // _headers.addAll(headers); // } // if (!kReleaseMode) { // print("Url:$url"); // var bodyJson = json.encode(jsonObject); // print("body:$bodyJson"); // } // var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); // if (!kReleaseMode) { // logger.i("res: " + response.body); // } // // var jsonData = jsonDecode(response.body); // GenericMapperModel res = GenericMapperModel.fromJson(jsonData); // if (jsonData["IsAuthenticated"] != null) { // AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; // } // // if (res.messageStatus == 1 && res.errorMessage == null) { // // return res.data; // return factoryConstructor(returnJsonData ? res.data : jsonData); // } else { // APIError? apiError; // apiError = APIError(jsonData['ErrorCode'], res.errorEndUserMessage, jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']); // throw APIException(APIException.BAD_REQUEST, error: apiError); // } // } // // Future postJsonForResponse(String url, T jsonObject, // {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { // String? requestBody; // late Map stringObj; // if (jsonObject != null) { // requestBody = jsonEncode(jsonObject); // if (headers == null) { // headers = {'Content-Type': 'application/json'}; // } else { // headers['Content-Type'] = 'application/json'; // } // } // // if (isFormData) { // headers = {'Content-Type': 'application/x-www-form-urlencoded'}; // stringObj = ((jsonObject ?? {}) as Map).map((key, value) => MapEntry(key, value?.toString() ?? "")); // } // // return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); // } // // Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { // try { // var _headers = {}; // if (token != null) { // _headers['Authorization'] = 'Bearer $token'; // } // // if (headers != null && headers.isNotEmpty) { // _headers.addAll(headers); // } // // if (queryParameters != null) { // var queryString = new Uri(queryParameters: queryParameters).query; // url = url + '?' + queryString; // } // var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(const Duration(seconds: 120)); // // if (response.statusCode >= 200 && response.statusCode < 300) { // return response; // } else { // throw _throwAPIException(response); // } // } on SocketException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } on HttpException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } on TimeoutException catch (e) { // throw APIException(APIException.TIMEOUT, arguments: e); // } on ClientException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } // } // // Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { // if (headers == null) { // headers = {'Content-Type': 'application/json'}; // } else { // headers['Content-Type'] = 'application/json'; // } // // if (!kReleaseMode) { // print("Url:$url"); // // var bodyJson = json.encode(jsonObject); // // print("body:$bodyJson"); // } // // return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); // } // // Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { // try { // var _headers = {}; // if (token != null) { // _headers['Authorization'] = 'Bearer $token'; // } // // if (headers != null && headers.isNotEmpty) { // _headers.addAll(headers); // } // // if (queryParameters != null) { // var queryString = new Uri(queryParameters: queryParameters).query; // url = url + '?' + queryString; // } // var response = await _get(Uri.parse(url), headers: _headers).timeout(const Duration(seconds: 60)); // // if (response.statusCode >= 200 && response.statusCode < 300) { // return response; // } else { // throw _throwAPIException(response); // } // } on SocketException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } on HttpException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } on TimeoutException catch (e) { // throw APIException(APIException.TIMEOUT, arguments: e); // } on ClientException catch (e) { // if (retryTimes > 0) { // print('will retry after 3 seconds...'); // await Future.delayed(const Duration(seconds: 3)); // return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); // } else { // throw APIException(APIException.OTHER, arguments: e); // } // } // } // // Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); // // bool _certificateCheck(X509Certificate cert, String host, int port) => true; // // Future _withClient(Future Function(Client) fn) async { // var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; // var client = IOClient(httpClient); // try { // return await fn(client); // } finally { // client.close(); // } // } // // Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); // } import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/generic_mapper_model.dart'; // ignore_for_file: avoid_annotating_with_dynamic typedef FactoryConstructor = U Function(dynamic); class APIError { int? errorCode; int? errorType; String? errorMessage; int? errorStatusCode; APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode); Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode}; @override String toString() { return jsonEncode(this); } } // class ApiResponse { // dynamic totalItemsCount; // List? data; // int? messageStatus; // dynamic errorMessage; // dynamic errorEndUserMessage; // // ApiResponse({ // this.totalItemsCount, // this.data, // this.messageStatus, // this.errorMessage, // this.errorEndUserMessage, // }); // // factory ApiResponse.fromRawJson(String str) => ApiResponse.fromJson(json.decode(str)); // // String toRawJson() => json.encode(toJson()); // // factory ApiResponse.fromJson(Map json) => ApiResponse( // totalItemsCount: json["TotalItemsCount"], // data: json["Data"] == null ? [] : List.from(json["Data"]!.map((x) => x)), // messageStatus: json["MessageStatus"], // errorMessage: json["ErrorMessage"], // errorEndUserMessage: json["ErrorEndUserMessage"], // ); // // Map toJson() => { // "TotalItemsCount": totalItemsCount, // "Data": data == null ? [] : List.from(data!.map((x) => x)), // "MessageStatus": messageStatus, // "ErrorMessage": errorMessage, // "ErrorEndUserMessage": errorEndUserMessage, // }; // // bool get isSuccess => messageStatus == 1 && errorMessage == null; // } // class ApiResponse { // final int? totalItemsCount; // final T data; // final int? messageStatus; // final String? errorMessage; // final String? errorEndUserMessage; // // final T Function(dynamic)? fromJsonT; // final String Function(T)? toJsonT; // // ApiResponse({ // required this.totalItemsCount, // required this.data, // required this.messageStatus, // this.errorMessage, // this.errorEndUserMessage, // this.fromJsonT, // this.toJsonT, // }); // // factory ApiResponse.fromJson( // Map json, // ) { // return ApiResponse( // totalItemsCount: json['totalItemsCount'], data: json['data'], messageStatus: json['messageStatus'], errorMessage: json['errorMessage'], errorEndUserMessage: json['errorEndUserMessage']); // } // // factory ApiResponse.fromRawJson(String str) => ApiResponse.fromJson(json.decode(str)); // // String toRawJson() { // if (toJsonT == null) { // throw Exception("toJsonT function is not provided for serialization."); // } // return json.encode(toJson()); // } // // Map toJson() { // if (toJsonT == null) { // throw Exception("toJsonT function is not provided for serialization."); // } // return { // "TotalItemsCount": totalItemsCount, // "Data": toJsonT!(data), // "MessageStatus": messageStatus, // "ErrorMessage": errorMessage, // "ErrorEndUserMessage": errorEndUserMessage, // }; // } // // bool get isSuccess => messageStatus == 1 && errorMessage == null; // } class ApiResponse { final dynamic totalItemsCount; final T? data; final dynamic messageStatus; final dynamic errorMessage; final dynamic errorEndUserMessage; ApiResponse({required this.totalItemsCount, required this.data, required this.messageStatus, this.errorMessage, this.errorEndUserMessage}); factory ApiResponse.fromRawJson(String str) => ApiResponse.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); factory ApiResponse.fromJson(Map json) => ApiResponse( totalItemsCount: json["TotalItemsCount"] ?? json["totalItemsCount"], data: json["Data"] ?? json["data"], messageStatus: json["MessageStatus"] ?? json["messageStatus"], errorMessage: json["ErrorMessage"] ?? json["errorMessage"], errorEndUserMessage: json["ErrorEndUserMessage"] ?? json["errorEndUserMessage"], ); Map toJson() => { "TotalItemsCount": totalItemsCount, "Data": data, "MessageStatus": messageStatus, "ErrorMessage": errorMessage, "ErrorEndUserMessage": errorEndUserMessage, }; bool get isSuccess => messageStatus == 1 && (errorMessage == null || errorMessage!.isEmpty); } APIException _throwAPIException(Response response) { switch (response.statusCode) { case 200: APIError? apiError; if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); print(jsonError); apiError = APIError( jsonError['ErrorCode'] ?? jsonError['errorCode'], jsonError['ErrorMessage'] ?? jsonError['errorMessage'], jsonError['ErrorType'] ?? jsonError['errorType'], jsonError['ErrorStatusCode'] ?? jsonError['errorStatusCode'], ); } return APIException(APIException.BAD_REQUEST, error: apiError); case 400: APIError? apiError; if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); apiError = APIError( jsonError['ErrorCode'] ?? jsonError['errorCode'], jsonError['ErrorMessage'] ?? jsonError['errorMessage'], jsonError['ErrorType'] ?? jsonError['errorType'], jsonError['ErrorStatusCode'] ?? jsonError['errorStatusCode'], ); } return APIException(APIException.BAD_REQUEST, error: apiError); case 401: return const APIException(APIException.UNAUTHORIZED); case 403: return const APIException(APIException.FORBIDDEN); case 404: return const APIException(APIException.NOT_FOUND); case 500: return const APIException(APIException.INTERNAL_SERVER_ERROR); case 444: var downloadUrl = response.headers["location"]; return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); default: return const APIException(APIException.OTHER); } } class ApiClient { static final ApiClient _instance = ApiClient._internal(); ApiClient._internal(); factory ApiClient() => _instance; Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false, bool returnJsonData = true}) async { var _headers = {'Accept': 'application/json'}; if (token != null && token.isNotEmpty && AppState().isLogged) { _headers['Authorization'] = 'Bearer $token'; } // logger.d(_headers); if (!kReleaseMode) { print("Url:$url"); var bodyJson = json.encode(jsonObject); printLongLog("body:$bodyJson"); } if (!_headers.containsKey('Authorization') && jsonObject is Map && jsonObject.containsKey('tokenID') && AppState().isLogged) { _headers['Authorization'] = 'Bearer ${jsonObject['tokenID']}'; } // Remove "logInTokenID" and "tokenID" from jsonObject if present // if (jsonObject is Map && AppState().isLogged) { // jsonObject.remove("logInTokenID"); // jsonObject.remove("tokenID"); // } var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); if (!kReleaseMode) { logger.i("res: ${response.body}"); } var jsonData = jsonDecode(response.body); // Handle authentication flag if present if (jsonData["IsAuthenticated"] != null) { print("IsAuthenticated Need to be upated: ${jsonData["IsAuthenticated"]}"); // // AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; } // Create ApiResponse from the json var apiResponse = ApiResponse.fromJson(jsonData); if (apiResponse.isSuccess) { return factoryConstructor(jsonData); } else { if (apiResponse.messageStatus == null || apiResponse.messageStatus != 1) { logger.i(apiResponse.errorMessage); throw APIException( APIException.OTHER, error: APIError( null, apiResponse.errorEndUserMessage ?? apiResponse.errorMessage, null, response.statusCode, ), ); } else { throw APIException( APIException.BAD_REQUEST, error: APIError( null, apiResponse.errorEndUserMessage ?? apiResponse.errorMessage, null, response.statusCode, ), ); } } } Future postJsonForResponse( String url, T jsonObject, { String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false, }) async { String? requestBody; late Map stringObj; if (jsonObject != null) { requestBody = jsonEncode(jsonObject); if (headers == null) { headers = {'Content-Type': 'application/json'}; } else { headers['Content-Type'] = 'application/json'; } } if (isFormData) { headers = {'Content-Type': 'application/x-www-form-urlencoded'}; stringObj = ((jsonObject ?? {}) as Map).map( (key, value) => MapEntry(key, value?.toString() ?? ""), ); } return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); } Future _postForResponse( String url, requestBody, { String? token, Map? queryParameters, Map? headers, int retryTimes = 0, }) async { try { var _headers = {}; if (token != null && AppState().isLogged) { _headers['Authorization'] = 'Bearer $token'; } if (headers != null && headers.isNotEmpty) { _headers.addAll(headers); } if (queryParameters != null) { var queryString = Uri(queryParameters: queryParameters).query; url = url + '?' + queryString; } var response = await _post( Uri.parse(url), body: requestBody, headers: _headers, ).timeout(const Duration(seconds: 120)); if (response.statusCode >= 200 && response.statusCode < 300) { return response; } else { throw _throwAPIException(response); } } on SocketException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse( url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } on HttpException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse( url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } on TimeoutException catch (e) { throw APIException(APIException.TIMEOUT, arguments: e); } on ClientException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse( url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } } Future getJsonForResponse( String url, { String? token, Map? queryParameters, Map? headers, int retryTimes = 0, }) async { if (headers == null) { headers = {'Content-Type': 'application/json'}; } else { headers['Content-Type'] = 'application/json'; } if (!kReleaseMode) { print("Url:$url"); } return await _getForResponse( url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, ); } Future getJsonForObject( FactoryConstructor factoryConstructor, String url, { String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool returnJsonData = true, }) async { var response = await getJsonForResponse( url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, ); var jsonData = jsonDecode(response.body); // Handle authentication flag if present if (jsonData["IsAuthenticated"] != null) { print("IsAuthenticated Need to be upated: ${jsonData["IsAuthenticated"]}"); // AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; } var apiResponse = ApiResponse.fromJson(jsonData); if (apiResponse.isSuccess) { return ApiResponse( totalItemsCount: apiResponse.totalItemsCount, data: apiResponse.data, messageStatus: apiResponse.messageStatus, errorMessage: apiResponse.errorMessage, errorEndUserMessage: apiResponse.errorEndUserMessage); } else { throw APIException( APIException.BAD_REQUEST, error: APIError(null, apiResponse.errorEndUserMessage ?? apiResponse.errorMessage, null, response.statusCode), ); } } Future _getForResponse( String url, { String? token, Map? queryParameters, Map? headers, int retryTimes = 0, }) async { try { var _headers = {}; if (token != null) { _headers['Authorization'] = 'Bearer $token'; } if (headers != null && headers.isNotEmpty) { _headers.addAll(headers); } if (queryParameters != null) { var queryString = Uri(queryParameters: queryParameters).query; url = url + '?' + queryString; } var response = await _get( Uri.parse(url), headers: _headers, ).timeout(const Duration(seconds: 60)); if (response.statusCode >= 200 && response.statusCode < 300) { return response; } else { throw _throwAPIException(response); } } on SocketException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _getForResponse( url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } on HttpException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _getForResponse( url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } on TimeoutException catch (e) { throw APIException(APIException.TIMEOUT, arguments: e); } on ClientException catch (e) { if (retryTimes > 0) { print('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _getForResponse( url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1, ); } else { throw APIException(APIException.OTHER, arguments: e); } } } Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); bool _certificateCheck(X509Certificate cert, String host, int port) => true; Future _withClient(Future Function(Client) fn) async { var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; var client = IOClient(httpClient); try { return await fn(client); } finally { client.close(); } } Future _post( url, { Map? headers, body, Encoding? encoding, }) => _withClient((client) => client.post( url, headers: headers, body: body, encoding: encoding, )); void printLongLog(String text) { var pattern = RegExp('.{1,1000}'); // Break into 1000-char chunks pattern.allMatches(text.replaceAll('\n', ' ')).forEach((match) => debugPrint(match.group(0))); } }