Files
intaleq_driver/lib/controller/functions/crud.dart
Hamza-Ayed 3c0ae4cf2f 26-1-20/1
2026-01-20 10:11:10 +03:00

914 lines
29 KiB
Dart
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:path/path.dart';
import 'package:sefer_driver/controller/functions/encrypt_decrypt.dart';
import 'package:sefer_driver/controller/functions/network/net_guard.dart';
import 'package:secure_string_operations/secure_string_operations.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/constant/links.dart';
import 'package:sefer_driver/controller/auth/captin/login_captin_controller.dart';
import 'package:sefer_driver/main.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:sefer_driver/env/env.dart';
import 'package:sefer_driver/print.dart';
import '../../constant/api_key.dart';
import '../../constant/char_map.dart';
import '../../constant/info.dart';
import '../../views/widgets/error_snakbar.dart';
import 'gemeni.dart';
import 'upload_image.dart';
class CRUD {
final NetGuard _netGuard = NetGuard();
final _client = http.Client();
/// Stores the signature of the last logged error to prevent duplicates.
static String _lastErrorSignature = '';
/// Stores the timestamp of the last logged error.
static DateTime _lastErrorTimestamp =
DateTime(2000); // Initialize with an old date
/// The minimum time that must pass before logging the same error again.
static const Duration _errorLogDebounceDuration = Duration(minutes: 1);
/// Asynchronously logs an error to the server with debouncing to prevent log flooding.
///
/// [error]: A concise description of the error.
/// [details]: Detailed information, such as a stack trace or the server response body.
/// [where]: The location in the code where the error occurred (e.g., 'ClassName.methodName').
static Future<void> addError(
String error, String details, String where) async {
try {
final currentErrorSignature = '$where-$error';
final now = DateTime.now();
if (currentErrorSignature == _lastErrorSignature &&
now.difference(_lastErrorTimestamp) < _errorLogDebounceDuration) {
return;
}
_lastErrorSignature = currentErrorSignature;
_lastErrorTimestamp = now;
final userId =
box.read(BoxName.driverID) ?? box.read(BoxName.passengerID);
final userType =
box.read(BoxName.driverID) != null ? 'Driver' : 'Passenger';
final phone = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
// Fire-and-forget call to prevent infinite loops if the logger itself fails.
CRUD().post(
link: AppLink.addError,
payload: {
'error': error.toString(),
'userId': userId.toString(),
'userType': userType,
'phone': phone.toString(),
'device': where,
'details': details,
},
);
} catch (e) {}
}
/// Centralized private method to handle all API requests.
/// Includes retry logic, network checking, and standardized error handling.
// --- تعديل 1: دالة _makeRequest محسنة للإنترنت الضعيف ---
Future<dynamic> _makeRequest({
required String link,
Map<String, dynamic>? payload,
required Map<String, String> headers,
}) async {
// 🟢 زيادة الوقت للسماح بالشبكات البطيئة (سوريا)
const connectTimeout = Duration(seconds: 20); // رفعنا الوقت من 6 لـ 20
const receiveTimeout = Duration(seconds: 40); // رفعنا الوقت من 10 لـ 40
Future<http.Response> doPost() {
final url = Uri.parse(link);
// نستخدم _client إذا كان معرفاً، أو ننشئ واحداً جديداً مع إغلاقه لاحقاً
// لضمان عدم حدوث مشاكل، سنستخدم http.post المباشر كما في النسخة المستقرة لديك
// ولكن مع timeout أطول
return http
.post(url, body: payload, headers: headers)
.timeout(connectTimeout + receiveTimeout);
}
http.Response response = http.Response('', 500); // Default initialization
// 🟢 محاولة إعادة الاتصال (Retry) حتى 3 مرات
int attempts = 0;
while (attempts < 3) {
try {
attempts++;
response = await doPost();
// إذا نجح الاتصال، نخرج من الحلقة ونعالج الرد
break;
} on SocketException catch (_) {
if (attempts >= 3) {
_netGuard.notifyOnce((title, msg) => mySnackeBarError(msg));
return 'no_internet';
}
// انتظار بسيط قبل المحاولة التالية (مهم جداً للشبكات المتقطعة)
await Future.delayed(const Duration(seconds: 1));
} on TimeoutException catch (_) {
if (attempts >= 3) return 'failure';
// لا ننتظر هنا، نعيد المحاولة فوراً
} catch (e) {
// إذا كان الخطأ هو errno = 9 (Bad file descriptor) نعيد المحاولة
if (e.toString().contains('errno = 9') && attempts < 3) {
await Future.delayed(const Duration(milliseconds: 500));
continue;
}
// أخطاء أخرى لا يمكن تجاوزها
addError(
'HTTP Exception: $e', 'Try: $attempts', 'CRUD._makeRequest $link');
return 'failure';
}
}
// --- معالجة الرد (كما هي في كودك) ---
// ملاحظة: المتغير response هنا قد يكون غير معرف (null) إذا فشلت كل المحاولات
// لكن بسبب الـ return داخل الـ catch، لن نصل هنا إلا بوجود response
// الحل الآمن لضمان وجود response قبل استخدامه:
try {
// إعادة تعريف response لضمان عدم حدوث خطأ null safety في المحرر
// (في المنطق الفعلي لن نصل هنا إلا ومعنا response)
if (attempts > 3) return 'failure';
final sc = response.statusCode; // استخدمنا ! لأننا متأكدين
final body = response.body;
if (sc >= 200 && sc < 300) {
try {
final jsonData = jsonDecode(body);
return jsonData;
} catch (e, st) {
addError('JSON Decode Error', 'Body: $body\n$st',
'CRUD._makeRequest $link');
return 'failure';
}
}
if (sc == 401) {
return 'token_expired';
}
if (sc >= 500) {
addError(
'Server 5xx', 'SC: $sc\nBody: $body', 'CRUD._makeRequest $link');
return 'failure';
}
return 'failure';
} catch (e) {
return 'failure';
}
}
// --- تعديل 2: دالة get (كما طلبت: بوست + إرجاع النص الخام) ---
// أبقيتها كما هي في كودك الأصلي تماماً، فقط حسنت الـ Timeout
Future<dynamic> get({
required String link,
Map<String, dynamic>? payload,
}) async {
try {
var url = Uri.parse(link);
// 🟢 إضافة timeout هنا أيضاً
var response = await http.post(
url,
body: payload,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization':
'Bearer ${r(box.read(BoxName.jwt)).toString().split(Env.addd)[0]}'
},
).timeout(const Duration(seconds: 40)); // وقت كافٍ للشبكات الضعيفة
Log.print('response: ${response.body}');
Log.print('response: ${response.request}');
if (response.statusCode == 200) {
// المنطق الخاص بك: إرجاع الـ body كاملاً كنص (String)
// لأنك تريد عمل jsonDecode لاحقاً في المكان الذي استدعى الدالة
// أو التحقق من status: success داخلياً
// ملاحظة: في كودك الأصلي كنت تفحص jsonDecode هنا وتعود بـ response.body
// سأبقيها كما هي:
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
return response.body; // إرجاع النص الخام
}
return jsonData['status'];
} else if (response.statusCode == 401) {
var jsonData = jsonDecode(response.body);
if (jsonData['error'] == 'Token expired') {
await Get.put(LoginDriverController()).getJWT();
return 'token_expired';
} else {
// addError('Unauthorized: ${jsonData['error']}', 'crud().get - 401',
// url.toString());
return 'failure';
}
} else {
addError('Non-200: ${response.statusCode}', 'crud().get - Other',
url.toString());
return 'failure';
}
} on TimeoutException {
// معالجة صامتة للتايم أوت في الـ GET
return 'failure';
} on SocketException {
// معالجة صامتة لانقطاع النت
return 'no_internet';
} catch (e) {
addError('GET Exception: $e', '', link);
return 'failure';
}
}
/// Performs a standard authenticated POST request.
/// Automatically handles token renewal.
Future<dynamic> post({
required String link,
Map<String, dynamic>? payload,
}) async {
String token = r(box.read(BoxName.jwt)).toString().split(Env.addd)[0];
// if (JwtDecoder.isExpired(token)) {
// await Get.put(LoginController()).getJWT();
// token = r(box.read(BoxName.jwt)).toString().split(Env.addd)[0];
// }
final headers = {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Bearer $token'
};
return await _makeRequest(
link: link,
payload: payload,
headers: headers,
);
}
/// Performs a standard authenticated GET request (using POST method as per original code).
/// Automatically handles token renewal.
/// Performs an authenticated POST request to wallet endpoints.
Future<dynamic> postWallet({
required String link,
Map<String, dynamic>? payload,
}) async {
var jwt = await LoginDriverController().getJwtWallet();
final hmac = box.read(BoxName.hmac);
final headers = {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Bearer $jwt',
'X-HMAC-Auth': hmac.toString(),
};
return await _makeRequest(
link: link,
payload: payload,
headers: headers,
);
}
/// Performs an authenticated GET request to wallet endpoints (using POST).
Future<dynamic> getWallet({
required String link,
Map<String, dynamic>? payload,
}) async {
var s = await LoginDriverController().getJwtWallet();
final hmac = box.read(BoxName.hmac);
var url = Uri.parse(
link,
);
var response = await http.post(
url,
body: payload,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Bearer $s',
'X-HMAC-Auth': hmac.toString(),
},
);
if (response.statusCode == 200) {
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
return response.body;
}
return jsonData['status'];
} else if (response.statusCode == 401) {
// Specifically handle 401 Unauthorized
var jsonData = jsonDecode(response.body);
if (jsonData['error'] == 'Token expired') {
// Show snackbar prompting to re-login
await Get.put(LoginDriverController()).getJwtWallet();
return 'token_expired'; // Return a specific value for token expiration
} else {
// Other 401 errors
addError('Unauthorized: ${jsonData['error']}', 'crud().post - 401',
url.toString());
return 'failure';
}
} else {
addError('Non-200 response code: ${response.statusCode}',
'crud().post - Other', url.toString());
return 'failure';
}
}
Future<dynamic> postWalletMtn(
{required String link, Map<String, dynamic>? payload}) async {
final s = await LoginDriverController().getJwtWallet();
final hmac = box.read(BoxName.hmac);
final url = Uri.parse(link);
try {
final response = await http.post(
url,
body: payload, // form-urlencoded مناسب لـ filterRequest
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer $s",
"X-HMAC-Auth": hmac.toString(),
},
);
Map<String, dynamic> wrap(String status, {Object? message, int? code}) {
return {
'status': status,
'message': message,
'code': code ?? response.statusCode,
};
}
if (response.statusCode == 200) {
try {
final jsonData = jsonDecode(response.body);
// نتوقع الآن شكل موحّد من السيرفر: {status, message, data?}
return jsonData;
} catch (e) {
return wrap('failure',
message: 'JSON decode error', code: response.statusCode);
}
} else if (response.statusCode == 401) {
try {
final jsonData = jsonDecode(response.body);
if (jsonData is Map && jsonData['error'] == 'Token expired') {
await Get.put(LoginDriverController()).getJWT();
return {
'status': 'failure',
'message': 'token_expired',
'code': 401
};
}
return wrap('failure', message: jsonData);
} catch (_) {
return wrap('failure', message: response.body);
}
} else {
// غير 200 ارجع التفاصيل
try {
final jsonData = jsonDecode(response.body);
return wrap('failure', message: jsonData);
} catch (_) {
return wrap('failure', message: response.body);
}
}
} catch (e) {
return {
'status': 'failure',
'message': 'HTTP request error: $e',
'code': -1
};
}
}
// Future<dynamic> postWallet(
// {required String link, Map<String, dynamic>? payload}) async {
// var s = await LoginDriverController().getJwtWallet();
// final hmac = box.read(BoxName.hmac);
// var url = Uri.parse(link);
// try {
// // await LoginDriverController().getJWT();
// var response = await http.post(
// url,
// body: payload,
// headers: {
// "Content-Type": "application/x-www-form-urlencoded",
// 'Authorization': 'Bearer $s',
// 'X-HMAC-Auth': hmac.toString(),
// },
// );
// if (response.statusCode == 200) {
// try {
// var jsonData = jsonDecode(response.body);
// if (jsonData['status'] == 'success') {
// return jsonData;
// } else {
// return jsonData['status'];
// }
// } catch (e) {
// // addError(e.toString(), 'crud().post - JSON decoding');
// return 'failure';
// }
// } else if (response.statusCode == 401) {
// // Specifically handle 401 Unauthorized
// var jsonData = jsonDecode(response.body);
// if (jsonData['error'] == 'Token expired') {
// return 'token_expired'; // Return a specific value for token expiration
// } else {
// // Other 401 errors
// // addError('Unauthorized: ${jsonData['error']}', 'crud().post - 401');
// return 'failure';
// }
// } else {
// // addError('Non-200 response code: ${response.statusCode}',
// // 'crud().post - Other');
// return 'failure';
// }
// } catch (e) {
// // addError('HTTP request error: $e', 'crud().post - HTTP');
// return 'failure';
// }
// }
// Future<dynamic> post(
// {required String link, Map<String, dynamic>? payload}) async {
// var url = Uri.parse(link);
// try {
// bool isTokenExpired = JwtDecoder.isExpired(X
// .r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs)
// .toString()
// .split(AppInformation.addd)[0]);
// if (isTokenExpired) {
// await LoginDriverController().getJWT();
// }
// var response = await http.post(
// url,
// body: payload,
// headers: {
// "Content-Type": "application/x-www-form-urlencoded",
// 'Authorization':
// 'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
// // 'Authorization': 'Bearer ${box.read(BoxName.jwt)}'
// },
// );
// if (response.statusCode == 200) {
// try {
// var jsonData = jsonDecode(response.body);
// if (jsonData['status'] == 'success') {
// return jsonData;
// } else {
// return jsonData['status'];
// }
// } catch (e) {
// // addError(e.toString(), url);
// return 'failure';
// }
// } else if (response.statusCode == 401) {
// // Specifically handle 401 Unauthorized
// var jsonData = jsonDecode(response.body);
// if (jsonData['error'] == 'Token expired') {
// // Show snackbar prompting to re-login
// // await Get.put(LoginDriverController()).getJWT();
// // MyDialog().getDialog(
// // 'Session expired. Please log in again.'.tr,
// // '',
// // () {
// // Get.put(LoginController()).loginUsingCredentials(
// // box.read(BoxName.passengerID), box.read(BoxName.email));
// // Get.back();
// // },
// // );
// return 'token_expired'; // Return a specific value for token expiration
// } else {
// // Other 401 errors
// // addError('Unauthorized: ${jsonData['error']}', 'crud().post - 401');
// return 'failure';
// }
// } else {
// // addError('Non-200 response code: ${response.statusCode}',
// // 'crud().post - Other');
// return 'failure';
// }
// } catch (e) {
// // addError('HTTP request error: $e', 'crud().post - HTTP');
// return 'failure';
// }
// }
Future<dynamic> getAgoraToken({
required String channelName,
required String uid,
}) async {
var uid = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
var res = await http.get(Uri.parse(
// 'https://repulsive-pig-rugby-shirt.cyclic.app/token?channelName=$channelName'),
'https://orca-app-b2i85.ondigitalocean.app/token?channelName=$channelName'),
headers: {'Authorization': 'Bearer ${AK.agoraAppCertificate}'});
if (res.statusCode == 200) {
var response = jsonDecode(res.body);
return response['token'];
} else {}
}
Future<dynamic> getLlama({
required String link,
required String payload,
required String prompt,
}) async {
var url = Uri.parse(
link,
);
var headers = {
'Content-Type': 'application/json',
'Authorization':
'Bearer LL-X5lJ0Px9CzKK0HTuVZ3u2u4v3tGWkImLTG7okGRk4t25zrsLqJ0qNoUzZ2x4ciPy'
// 'Authorization': 'Bearer ${Env.llamaKey}'
};
var data = json.encode({
"model": "Llama-3-70b-Inst-FW",
// "model": "llama-13b-chat",
"messages": [
{
"role": "user",
"content":
"Extract the desired information from the following passage as json decoded like $prompt just in this:\n\n$payload"
}
],
"temperature": 0.9
});
var response = await http.post(
url,
body: data,
headers: headers,
);
if (response.statusCode == 200) {
return response.body;
}
return response.statusCode;
}
Future allMethodForAI(String prompt, linkPHP, imagePath) async {
await ImageController().choosImage(linkPHP, imagePath);
Future.delayed(const Duration(seconds: 2));
var extractedString =
await arabicTextExtractByVisionAndAI(imagePath: imagePath);
var json = jsonDecode(extractedString);
var textValues = extractTextFromLines(json);
// await Get.put(AI()).geminiAiExtraction(prompt, textValues);
await Get.put(AI()).anthropicAI(textValues, prompt, imagePath);
}
String extractTextFromLines(Map<String, dynamic> jsonData) {
final readResult = jsonData['readResult'];
final blocks = readResult['blocks'];
final StringBuffer buffer = StringBuffer();
for (final block in blocks) {
final lines = block['lines'];
for (final line in lines) {
final text = line['text'];
buffer.write(text);
buffer.write('\n');
}
}
return buffer.toString().trim();
}
Future<dynamic> arabicTextExtractByVisionAndAI({
required String imagePath,
}) async {
var headers = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': AK.ocpApimSubscriptionKey
};
String imagePathFull =
'${AppLink.server}/card_image/$imagePath-${box.read(BoxName.driverID)}.jpg';
var request = http.Request('POST', Uri.parse(
// 'https://ocrhamza.cognitiveservices.azure.com/vision/v2.1/ocr?language=ar'));
// 'https://eastus.api.cognitive.microsoft.com/vision/v3.2/ocr'
'https://eastus.api.cognitive.microsoft.com/computervision/imageanalysis:analyze?features=caption,read&model-version=latest&language=en&api-version=2024-02-01'));
request.body = json.encode({"url": imagePathFull});
// request.body = json.encode({"url": imagePathFull});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// 'response.stream.bytesToString(): ${await response.stream.bytesToString()}');
return await response.stream.bytesToString();
} else {}
}
Future<dynamic> getChatGPT({
required String link,
required String payload,
}) async {
var url = Uri.parse(
link,
);
var headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ${Env.chatGPTkeySeferNew}'
};
var data = json.encode({
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content":
"Extract the desired information from the following passage as json decoded like vin,make,made,year,expiration_date,color,owner,registration_date just in this:\n\n$payload"
}
],
"temperature": 0.9
});
var response = await http.post(
url,
body: data,
headers: headers,
);
if (response.statusCode == 200) {
return response.body;
}
return response.statusCode;
}
Future<dynamic> postStripe({
required String link,
Map<String, dynamic>? payload,
}) async {
// String? secretKey = await storage.read(key: BoxName.secretKey);
var url = Uri.parse(
link,
);
var response = await http.post(
url,
body: payload,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Bearer ${AK.secretKeyStripe}',
},
);
if (response.statusCode == 200) {
return response.body;
} else {}
}
Future<dynamic> postPayMob({
required String link,
Map<String, dynamic>? payload,
}) async {
// String? basicAuthCredentials =
// await storage.read(key: BoxName.basicAuthCredentials);
var url = Uri.parse(
link,
);
var response = await http.post(url,
body: payload, headers: {'Content-Type': 'application/json'});
var jsonData = jsonDecode(response.body);
if (response.statusCode == 200) {
if (jsonData['status'] == 'success') {
return response.body;
} else {
return (jsonData['status']);
}
} else {
return response.statusCode;
}
}
Future<void> sendEmail(String link, Map<String, String>? payload) async {
// التحقق من صلاحية التوكن
String rawJwt = box.read(BoxName.jwt);
String token = X
.r(X.r(X.r(rawJwt, cn), cC), cs)
.toString()
.split(AppInformation.addd)[0];
bool isTokenExpired = JwtDecoder.isExpired(token);
if (isTokenExpired) {
await LoginDriverController().getJWT();
rawJwt = box.read(BoxName.jwt); // تحديث التوكن بعد التجديد
token = X
.r(X.r(X.r(rawJwt, cn), cC), cs)
.toString()
.split(AppInformation.addd)[0];
}
// إعداد الهيدر
final headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer $token",
};
// إعداد الطلب
final request = http.Request('POST', Uri.parse(link));
request.bodyFields = payload ?? {};
request.headers.addAll(headers);
// إرسال الطلب
final response = await request.send();
// التحقق من النتيجة
if (response.statusCode == 200) {
} else {
final responseBody = await response.stream.bytesToString();
}
}
Future<dynamic> postFromDialogue({
required String link,
Map<String, dynamic>? payload,
}) async {
// String? basicAuthCredentials =
// await storage.read(key: BoxName.basicAuthCredentials);
var url = Uri.parse(
link,
);
var response = await http.post(
url,
body: payload,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization':
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
},
);
if (response.body.isNotEmpty) {
var jsonData = jsonDecode(response.body);
if (response.statusCode == 200) {
if (jsonData['status'] == 'success') {
Get.back();
// Get.snackbar(
// jsonData['status'],
// jsonData['message'],
// );
return response.body;
}
}
return (jsonData['status']);
}
}
Future<void> sendVerificationRequest(String phoneNumber) async {
final accountSid = AK.accountSIDTwillo;
final authToken = AK.authTokenTwillo;
final verifySid = AK.twilloRecoveryCode;
final Uri verificationUri = Uri.parse(
'https://verify.twilio.com/v2/Services/$verifySid/Verifications');
// Send the verification request
final response = await http.post(
verificationUri,
headers: {
'Authorization':
'Basic ' + base64Encode(utf8.encode('$accountSid:$authToken')),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'To': phoneNumber,
'Channel': 'sms',
},
);
if (response.statusCode == 201) {
} else {}
// Prompt the user to enter the OTP
final otpCode = "123456"; // Replace with user input
// Check the verification code
final checkUri = Uri.parse(
'https://verify.twilio.com/v2/Services/$verifySid/VerificationCheck');
final checkResponse = await http.post(
checkUri,
headers: {
'Authorization':
'Basic ' + base64Encode(utf8.encode('$accountSid:$authToken')),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'To': phoneNumber,
'Code': otpCode,
},
);
if (checkResponse.statusCode == 201) {
} else {}
}
Future<dynamic> getGoogleApi({
required String link,
Map<String, dynamic>? payload,
}) async {
var url = Uri.parse(
link,
);
var response = await http.post(
url,
body: payload,
);
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'OK') {
return jsonData;
}
return (jsonData['status']);
}
Future<dynamic> update({
required String endpoint,
required Map<String, dynamic> data,
required String id,
}) async {
// String? basicAuthCredentials =
// await storage.read(key: BoxName.basicAuthCredentials);
var url = Uri.parse('$endpoint/$id');
var response = await http.put(
url,
body: json.encode(data),
headers: {
'Authorization':
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
},
);
return json.decode(response.body);
}
Future<dynamic> delete({
required String endpoint,
required String id,
}) async {
// String? basicAuthCredentials =
// await storage.read(key: BoxName.basicAuthCredentials);
var url = Uri.parse('$endpoint/$id');
var response = await http.delete(
url,
headers: {
'Authorization':
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
},
);
return json.decode(response.body);
}
}
/// Custom exception for when there is no internet connection.
class NoInternetException implements Exception {
final String message;
NoInternetException(
[this.message =
'No internet connection. Please check your network and try again.']);
@override
String toString() => message;
}
/// Custom exception for when the network is too slow (request times out).
class WeakNetworkException implements Exception {
final String message;
WeakNetworkException(
[this.message =
'Your network connection is too slow. Please try again later.']);
@override
String toString() => message;
}
class ApiException implements Exception {
final String message;
final int? statusCode;
ApiException(this.message, [this.statusCode]);
@override
String toString() =>
"ApiException: $message (Status Code: ${statusCode ?? 'N/A'})";
}