diff --git a/android/app/build.gradle b/android/app/build.gradle index ea8298ff..69a0b567 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -38,8 +38,8 @@ android { ndkVersion flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } defaultConfig { diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index df0436b5..69e5989b 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -97,6 +97,37 @@ class ApiClient { } } + Future putJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { + var defaultHeaders = {'Accept': 'application/json'}; + if (headers != null && headers.isNotEmpty) { + defaultHeaders.addAll(headers); + } + if (!kReleaseMode) { + debugPrint("Url:$url"); + var bodyJson = json.encode(jsonObject); + debugPrint("body:$bodyJson"); + } + var response = await putJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isFormData: isFormData); + try { + var jsonData = jsonDecode(response.body); + if (jsonData != null) { + debugPrint(jsonData.runtimeType.toString()); + return factoryConstructor(jsonData); + } else { + APIError? apiError; + apiError = APIError(response.statusCode, jsonData[0]); + throw APIException(APIException.BAD_REQUEST, error: apiError); + } + } catch (ex) { + if (ex is APIException) { + rethrow; + } else { + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + } + Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = true}) async { int currentRetryTime = retryTimes; @@ -115,6 +146,10 @@ class ApiClient { headers = {'Content-Type': 'application/x-www-form-urlencoded'}; stringObj = ((jsonObject ?? {}) as Map).map((key, value) => MapEntry(key, value?.toString() ?? "")); } + if (!kReleaseMode) { + print("url:$url"); + print("requestBody:$requestBody"); + } Future retry(APIException exception) async { if (currentRetryTime > 0) { currentRetryTime -= 1; @@ -139,6 +174,52 @@ class ApiClient { } } + Future putJsonForResponse(String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = true}) async { + int currentRetryTime = retryTimes; + 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() ?? "")); + } + if (!kReleaseMode) { + print("url:$url"); + print("requestBody:$requestBody"); + } + Future retry(APIException exception) async { + if (currentRetryTime > 0) { + currentRetryTime -= 1; + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _putForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers); + } else { + throw exception; + } + } + + try { + return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers); + } on SocketException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } on HttpException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } + } + Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers}) async { var defaultHeaders = {}; if (token != null) { @@ -162,32 +243,49 @@ class ApiClient { } } - Future getJsonForObject(FactoryConstructor factoryConstructor, String url, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = true}) async { - var defaultHeaders = {'Accept': 'application/json'}; + Future _putForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers}) async { + var defaultHeaders = {}; + if (token != null) { + defaultHeaders['Authorization'] = 'Bearer $token'; + } + if (headers != null && headers.isNotEmpty) { defaultHeaders.addAll(headers); } - if (!kReleaseMode) { - debugPrint("Url:$url"); + + if (queryParameters != null) { + var queryString = Uri(queryParameters: queryParameters).query; + url = '$url?$queryString'; } - var response = await getJsonForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); - try { - var jsonData = jsonDecode(response.body.replaceAll(r"\'", "'")); - if (jsonData != null) { - debugPrint(jsonData.runtimeType.toString()); - return factoryConstructor(jsonData); - } else { - APIError? apiError; - apiError = APIError(response.statusCode, jsonData[0]); - throw APIException(APIException.BAD_REQUEST, error: apiError); - } - } catch (ex) { - if (ex is APIException) { - rethrow; - } else { - throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); - } + var response = await _put(Uri.parse(url), body: requestBody, headers: defaultHeaders).timeout(const Duration(seconds: 120)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); + } + } + + Future _deleteForResponse(String url, {String? token, Map? queryParameters, Map? headers}) async { + var defaultHeaders = {}; + if (token != null) { + defaultHeaders['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + defaultHeaders.addAll(headers); + } + + if (queryParameters != null) { + var queryString = Uri(queryParameters: queryParameters).query; + url = '$url?$queryString'; + } + var response = await _delete(Uri.parse(url), headers: defaultHeaders).timeout(const Duration(seconds: 60)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); } } @@ -222,6 +320,37 @@ class ApiClient { } } + Future deleteJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + int currentRetryTime = retryTimes; + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + Future retry(APIException exception) async { + if (currentRetryTime > 0) { + currentRetryTime -= 1; + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _deleteForResponse(url, token: token, queryParameters: queryParameters, headers: headers); + } else { + throw exception; + } + } + + try { + return await _deleteForResponse(url, token: token, queryParameters: queryParameters, headers: headers); + } on SocketException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } on HttpException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + return await retry(APIException(APIException.OTHER, arguments: e)); + } + } + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers}) async { var defaultHeaders = {}; if (token != null) { @@ -236,12 +365,6 @@ class ApiClient { var queryString = Uri(queryParameters: queryParameters).query; url = '$url?$queryString'; } - - if (!kReleaseMode) { - debugPrint("Url:$url"); - debugPrint("queryParameters:$queryParameters"); - debugPrint("headers:$defaultHeaders"); - } var response = await _get(Uri.parse(url), headers: defaultHeaders).timeout(const Duration(seconds: 60)); if (response.statusCode >= 200 && response.statusCode < 300) { @@ -266,4 +389,8 @@ class ApiClient { } Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); + + Future _put(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.put(url, headers: headers, body: body, encoding: encoding)); + + Future _delete(url, {Map? headers}) => _withClient((client) => client.delete(url, headers: headers)); }