Files
intaleq_driver/lib/controller/functions/crud.dart
2025-09-21 15:02:12 +03:00

945 lines
30 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:convert';
import 'dart:io';
import 'package:jwt_decoder/jwt_decoder.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 '../../constant/api_key.dart';
import '../../constant/char_map.dart';
import '../../constant/info.dart';
import '../../views/widgets/error_snakbar.dart';
import '../../print.dart';
import 'gemeni.dart';
import 'network/connection_check.dart';
import 'upload_image.dart';
class CRUD {
final NetGuard _netGuard = NetGuard();
/// 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 {
// Create a unique signature for the current error
final currentErrorSignature = '$where-$error';
final now = DateTime.now();
// Check if the same error occurred recently
if (currentErrorSignature == _lastErrorSignature &&
now.difference(_lastErrorTimestamp) < _errorLogDebounceDuration) {
// If it's the same error within the debounce duration, ignore it.
print("Debounced a duplicate error: $error");
return;
}
// Update the signature and timestamp for the new error
_lastErrorSignature = currentErrorSignature;
_lastErrorTimestamp = now;
// Get user information for the error log
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);
// Send the error data to the server
// Note: This is a fire-and-forget call. We don't await it or handle its response
// to prevent an infinite loop if the addError endpoint itself is failing.
CRUD().post(
link: AppLink.addError,
payload: {
'error': error.toString(),
'userId': userId.toString(),
'userType': userType,
'phone': phone.toString(),
'device': where, // The location of the error
'details': details, // The detailed stack trace or context
},
);
} catch (e) {
// If logging the error itself fails, print to the console to avoid infinite loops.
print("Failed to log error to server: $e");
}
}
Future<dynamic> _makeRequest({
required String link,
Map<String, dynamic>? payload,
required Map<String, String> headers,
}) async {
try {
// 1. Wrap the http.post call directly with HttpRetry.sendWithRetry.
// It will attempt the request immediately and retry on transient errors.
var response = await HttpRetry.sendWithRetry(
() {
var url = Uri.parse(link);
return http.post(
url,
body: payload,
headers: headers,
);
},
// Optional: you can customize retry behavior for each call
maxRetries: 3,
timeout: const Duration(seconds: 15),
);
// Log.print('response: ${response.body}');
// Log.print('request: ${response.request}');
// Log.print('payload: ${payload}');
// ✅ All your existing logic for handling server responses remains the same.
// This part is only reached if the network request itself was successful.
// Handle successful response (200 OK)
if (response.statusCode == 200) {
try {
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
return jsonData; // Return the full JSON object on success
} else {
if (jsonData['status'] == 'failure') {
// return 'failure';
} else {
addError(
'API Logic Error: ${jsonData['status']}',
'Response: ${response.body}',
'CRUD._makeRequest - $link',
);
}
return jsonData['status']; // Return the specific status string
}
} catch (e, stackTrace) {
addError(
'JSON Decode Error: $e',
'Response Body: ${response.body}\nStack Trace: $stackTrace',
'CRUD._makeRequest - $link',
);
return 'failure';
}
}
// Handle Unauthorized (401)
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 Error: ${jsonData['error']}',
'Status Code: 401',
'CRUD._makeRequest - $link',
);
return 'failure';
}
}
// Handle all other non-successful status codes
else {
addError(
'HTTP Error',
'Status Code: ${response.statusCode}\nResponse Body: ${response.body}',
'CRUD._makeRequest - $link',
);
return 'failure';
}
} on SocketException {
// 2. This block now catches the "no internet" case after all retries have failed.
_netGuard.notifyOnce((title, msg) {
mySnackeBarError(msg);
});
return 'no_internet'; // Return the specific status you were using before.
} catch (e, stackTrace) {
// 3. This is a general catch-all for any other unexpected errors.
addError(
'HTTP Request Exception: $e',
'Stack Trace: $stackTrace',
'CRUD._makeRequest - $link',
);
return 'failure';
}
}
Future<dynamic> post({
required String link,
Map<String, dynamic>? payload,
}) async {
// 1. Check if the token is expired
// bool isTokenExpired = JwtDecoder.isExpired(X
// .r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs)
// .toString()
// .split(AppInformation.addd)[0]);
// // 2. If expired, get a new one
// if (isTokenExpired) {
// await LoginDriverController().getJWT();
// }
// 3. Prepare the headers with the valid token
final 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]}'
};
// 4. Make the request using the centralized helper
return await _makeRequest(
link: link,
payload: payload,
headers: headers,
);
}
/// Performs an authenticated POST request to the wallet endpoints.
/// Uses a separate JWT and HMAC for authentication.
Future<dynamic> postWallet({
required String link,
Map<String, dynamic>? payload,
}) async {
// 1. Get the specific JWT and HMAC for the wallet
var jwt = await LoginDriverController().getJwtWallet();
final hmac = box.read(BoxName.hmac);
// 2. Prepare the headers
final headers = {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Bearer $jwt',
'X-HMAC-Auth': hmac.toString(),
};
// 3. Make the request using the centralized helper
return await _makeRequest(
link: link,
payload: payload,
headers: headers,
);
}
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(),
},
);
print('req: ${response.request}');
print('status: ${response.statusCode}');
print('body: ${response.body}');
print('payload: $payload');
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> get({
required String link,
Map<String, dynamic>? payload,
}) async {
// bool isTokenExpired = JwtDecoder.isExpired(X
// .r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs)
// .toString()
// .split(AppInformation.addd)[0]);
// // Log.print('isTokenExpired: ${isTokenExpired}');
// if (isTokenExpired) {
// await LoginDriverController().getJWT();
// }
// await Get.put(LoginDriverController()).getJWT();
var url = Uri.parse(
link,
);
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]}'
},
);
// print(response.request);
// Log.print('response.body: ${response.body}');
// print(payload);
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()).getJWT();
// mySnackbarSuccess('please order now'.tr);
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';
}
}
Future<dynamic> getWallet({
required String link,
Map<String, dynamic>? payload,
}) async {
var s = await LoginDriverController().getJwtWallet();
final hmac = box.read(BoxName.hmac);
// Log.print('hmac: ${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(),
},
);
// Log.print('response.request: ${response.request}');
// Log.print('response.body: ${response.body}');
// print(payload);
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');
return 'failure';
}
} else {
// addError('Non-200 response code: ${response.statusCode}',
// 'crud().post - Other');
return 'failure';
}
}
// Future<dynamic> postWallet(
// {required String link, Map<String, dynamic>? payload}) async {
// var s = await LoginDriverController().getJwtWallet();
// // Log.print('jwt: ${s}');
// final hmac = box.read(BoxName.hmac);
// // Log.print('hmac: ${hmac}');
// var url = Uri.parse(link);
// // Log.print('url: ${url}');
// 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(),
// },
// );
// // Log.print('response.request:${response.request}');
// // Log.print('response.body: ${response.body}');
// // Log.print('payload:$payload');
// 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)}'
// },
// );
// print(response.request);
// Log.print('response.body: ${response.body}');
// print(payload);
// 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) {
print("✅ Email sent successfully.");
} else {
print("❌ Failed to send email. Status: ${response.statusCode}");
final responseBody = await response.stream.bytesToString();
print("Response body: $responseBody");
}
}
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,
);
Log.print('esponse.body: ${response.body}');
Log.print('esponse.body: ${response.request}');
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'})";
}