import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'dart:ui' as ui; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:customer/controllers/theme_controller.dart'; import 'package:customer/models/currency_model.dart'; import 'package:customer/models/order_model.dart'; import 'package:customer/models/tax_model.dart'; import 'package:customer/models/user_model.dart'; import 'package:customer/models/vendor_model.dart'; import 'package:customer/models/zone_model.dart'; import 'package:customer/themes/app_them_data.dart'; import 'package:customer/utils/preferences.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart' as geolocator; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart' hide Trans; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:intl/intl.dart'; import 'package:mailer/mailer.dart'; import 'package:mailer/smtp_server.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:uuid/uuid.dart'; import '../models/cart_product_model.dart'; import '../models/coupon_model.dart'; import '../models/email_template_model.dart'; import '../models/language_model.dart'; import '../models/mail_setting.dart'; import '../models/section_model.dart'; import '../service/fire_store_utils.dart'; import '../themes/show_toast_dialog.dart'; import '../widget/permission_dialog.dart'; import 'package:http/http.dart' as http; RxList cartItem = [].obs; class Constant { static const userPlaceHolder = "assets/images/user_placeholder.png"; static String senderId = ''; static String jsonNotificationFileURL = ''; static String appVersion = ''; static List taxList = []; static String? country = ""; static String? selectedMapType = ""; static String? websiteUrl = ''; static MailSettings? mailSettings; static bool isSubscriptionModelApplied = false; static CurrencyModel? currencyData; static SectionModel? sectionConstantModel; static geolocator.Position? currentLocation; static String cabServiceType = "cab-service"; static String parcelServiceType = "parcel-service"; static bool isZoneAvailable = false; static ZoneModel? selectedZone; static List zoneList = []; static List sectionColor = [ [Color(0xFFFEF8E7), Color(0xFFF7CD59)], [Color(0xFFEEEBF9), Color(0xFF8F7CD8)], [Color(0xFFFFF8E5), Color(0xFFF7CD59)], [Color(0xFFF5E5FF), Color(0xFFCC80FF)], [Color(0xFFFAEBEB), Color(0xFFDB7474)], [Color(0xFFE5F9FF), Color(0xFF72DEFF)], [Color(0xFFEFF5F1), Color(0xFFADCEB7)], [Color(0xFFEAFBF1), Color(0xFF85E5AE)], [Color(0xFFE7F8FE), Color(0xFF529DB6)], [Color(0xFFEEEBF9), Color(0xFF8F7CD8)], ]; static List colorList = [ Color(0xFFFFBC99), const Color(0xFFCABDFF), const Color(0xFFB1E5FC), const Color(0xFFB5EBCD), const Color(0xFFFFD88D), const Color(0xFFCBEBA4), const Color(0xFFFB9B9B), const Color(0xFFF8B0ED), const Color(0xFFAFC6FF), ]; static String userRoleDriver = 'driver'; static String userRoleCustomer = 'customer'; static String userRoleVendor = 'vendor'; static ShippingAddress selectedLocation = ShippingAddress(); static UserModel? userModel; static const globalUrl = "https://Replace_your_domain/"; static String mapAPIKey = ""; static String placeHolderImage = ""; static String defaultCountryCode = ""; static String defaultCountry = ""; static bool isCashbackActive = false; static bool isEnableOTPTripStart = false; static bool isEnableOTPTripStartForRental = false; static bool isMaintenanceModeForCustomer = false; static String distanceType = "km"; static String googlePlayLink = ""; static String appStoreLink = ""; static String termsAndConditions = ""; static String privacyPolicy = ""; static String supportURL = ""; static String minimumAmountToDeposit = "0.0"; static String minimumAmountToWithdrawal = "0.0"; static bool? walletSetting = true; static bool? storyEnable = true; static bool? specialDiscountOffer = true; static const String orderPlaced = "Order Placed"; static const String orderAccepted = "Order Accepted"; static const String orderRejected = "Order Rejected"; static const String orderCancelled = "Order Cancelled"; static const String driverPending = "Driver Pending"; static const String driverRejected = "Driver Rejected"; static const String driverAccepted = 'Driver Accepted'; static const String orderShipped = "Order Shipped"; static const String orderInTransit = "In Transit"; static const String orderCompleted = "Order Completed"; static const String orderAssigned = "Order Assigned"; static const String orderOngoing = "Order Ongoing"; static const String bookingPlaced = "booking_placed"; static CurrencyModel? currencyModel; static List? restaurantList = []; static String walletTopup = "wallet_topup"; static String newVendorSignup = "new_vendor_signup"; static String payoutRequestStatus = "payout_request_status"; static String payoutRequest = "payout_request"; static String newOrderPlaced = "order_placed"; static String scheduleOrder = "schedule_order"; static String dineInPlaced = "dinein_placed"; static String dineInCanceled = "dinein_canceled"; static String dineinAccepted = "dinein_accepted"; static String restaurantRejected = "restaurant_rejected"; static String driverCompleted = "driver_completed"; static String restaurantAccepted = "restaurant_accepted"; static String takeawayCompleted = "takeaway_completed"; static String newParcelBook = "new_parcel_book"; static String newOnDemandBook = "new_ondemand_book"; // static String selectedMapType = 'osm'; static String? mapType = "google"; static String? we = "google"; static bool isEnableAdsFeature = true; static bool isSelfDeliveryFeature = false; static double getDoubleVal(dynamic input) { if (input == null) return 0.1; if (input is int) return input.toDouble(); if (input is double) return input; return 0.1; } static bool checkZoneCheck(double latitude, double longLatitude) { bool isZoneAvailable = false; for (var element in Constant.zoneList) { if (Constant.isPointInPolygon( LatLng(latitude, longLatitude), element.area!, )) { isZoneAvailable = true; break; } else { isZoneAvailable = false; } } return isZoneAvailable; } static String? getZoneId(double latitude, double longLatitude) { String? zoneId; for (var element in Constant.zoneList) { if (Constant.isPointInPolygon( LatLng(latitude, longLatitude), element.area!, )) { zoneId = element.id; break; } } return zoneId; } static String getReferralCode() { var rng = Random(); return (rng.nextInt(900000) + 100000).toString(); // 6 digit } static Future checkPermission({ required BuildContext context, required Function() onTap, }) async { LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); } if (permission == LocationPermission.denied) { ShowToastDialog.showToast( "You have to allow location permission to use your location", ); } else if (permission == LocationPermission.deniedForever) { showDialog( context: context, builder: (BuildContext context) { return const PermissionDialog(); }, ); } else { onTap(); } } static bool get isRtl { final locale = Get.locale ?? Get.deviceLocale ?? const Locale('en'); return Bidi.isRtlLanguage(locale.languageCode); } static bool isExpire(VendorModel venderModel) { bool isPlanExpire = false; if (venderModel.subscriptionPlan?.id != null) { if (venderModel.subscriptionExpiryDate == null) { if (venderModel.subscriptionPlan?.expiryDay == '-1') { isPlanExpire = false; } else { isPlanExpire = true; } } else { DateTime expiryDate = venderModel.subscriptionExpiryDate!.toDate(); isPlanExpire = expiryDate.isBefore(DateTime.now()); } } else { isPlanExpire = true; } return isPlanExpire; } static bool isExpireDate({ required bool expiryDay, Timestamp? subscriptionExpiryDate, }) { bool isPlanExpire = false; if (expiryDay == true) { isPlanExpire = false; } else { if (subscriptionExpiryDate != null) { DateTime expiryDate = subscriptionExpiryDate.toDate(); isPlanExpire = expiryDate.isBefore(DateTime.now()); } else { isPlanExpire = true; } } return isPlanExpire; } static Future showProgress(String message, bool isDismissible) async { ShowToastDialog.showLoader("$message "); } static void hideProgress() { ShowToastDialog.closeLoader(); } static String amountShow({required String? amount}) { if (currencyModel!.symbolatright == true) { return "${double.parse(amount.toString()).toStringAsFixed(currencyModel?.decimal ?? 0)} ${currencyModel!.symbol.toString()}"; } else { return "${currencyModel!.symbol.toString()} ${amount == null || amount.isEmpty ? "0.0" : double.parse(amount.toString()).toStringAsFixed(currencyModel?.decimal ?? 0)}"; } } static Color statusColor({required String? status}) { if (status == orderPlaced) { return AppThemeData.ecommerce300; } else if (status == orderAccepted || status == orderCompleted) { return AppThemeData.success400; } else if (status == orderRejected) { return AppThemeData.danger300; } else { return AppThemeData.warning300; } } static Color statusText({required String? status}) { if (status == orderPlaced) { return AppThemeData.grey50; } else if (status == orderAccepted || status == orderCompleted) { return AppThemeData.grey50; } else if (status == orderRejected) { return AppThemeData.grey50; } else { return AppThemeData.grey900; } } static String productCommissionPrice(VendorModel vendorModel, String price) { String commission = "0"; if (sectionConstantModel!.adminCommision!.isEnabled == true) { if (vendorModel.adminCommission == null) { if (sectionConstantModel!.adminCommision!.commissionType! .toLowerCase() == "Percent".toLowerCase() || sectionConstantModel!.adminCommision!.commissionType ?.toLowerCase() == "Percentage".toLowerCase()) { commission = (double.parse(price) + (double.parse(price) * double.parse( sectionConstantModel!.adminCommision!.amount .toString(), ) / 100)) .toString(); } else { commission = (double.parse(price) + double.parse( sectionConstantModel!.adminCommision!.amount.toString(), )) .toString(); } } else { if (vendorModel.adminCommission!.commissionType!.toLowerCase() == "Percent".toLowerCase() || vendorModel.adminCommission!.commissionType?.toLowerCase() == "Percentage".toLowerCase()) { commission = (double.parse(price) + (double.parse(price) * double.parse( vendorModel.adminCommission!.amount.toString(), ) / 100)) .toString(); } else { commission = (double.parse(price) + double.parse( vendorModel.adminCommission!.amount.toString(), )) .toString(); } } } else { commission = price; } return commission; } static double calculateTax({String? amount, TaxModel? taxModel}) { double taxAmount = 0.0; if (taxModel != null && taxModel.enable == true) { if (taxModel.type == "fix") { taxAmount = double.parse(taxModel.tax.toString()); } else { taxAmount = (double.parse(amount.toString()) * double.parse(taxModel.tax!.toString())) / 100; } } return taxAmount; } static double calculateDiscount({String? amount, CouponModel? offerModel}) { double taxAmount = 0.0; if (offerModel != null) { if (offerModel.discountType == "Percentage" || offerModel.discountType == "percentage") { taxAmount = (double.parse(amount.toString()) * double.parse(offerModel.discount.toString())) / 100; } else { taxAmount = double.parse(offerModel.discount.toString()); } } return taxAmount; } static String calculateReview({ required String? reviewCount, required String? reviewSum, }) { if (0 == double.parse(reviewSum.toString()) && 0 == double.parse(reviewSum.toString())) { return "0"; } return (double.parse(reviewSum.toString()) / double.parse(reviewCount.toString())) .toStringAsFixed(1); } static String getUuid() { return const Uuid().v4(); } static Widget loader() { return Center( child: CircularProgressIndicator(color: AppThemeData.primary300), ); } static Widget showEmptyView({required String message}) { final themeController = Get.find(); final isDark = themeController.isDark.value; return Center( child: Text( message, style: TextStyle( fontFamily: AppThemeData.fontFamily, fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, ), ), ); } static String maskingString(String documentId, int maskingDigit) { String maskedDigits = documentId; for (int i = 0; i < documentId.length - maskingDigit; i++) { maskedDigits = maskedDigits.replaceFirst(documentId[i], "*"); } return maskedDigits; } String? validateRequired(String? value, String type) { if (value!.isEmpty) { return '$type required'; } return null; } String? validateEmail(String? value) { String pattern = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; RegExp regExp = RegExp(pattern); if (value == null || value.isEmpty) { return "Email is Required"; } else if (!regExp.hasMatch(value)) { return "Invalid Email"; } else { return null; } } static String getDistance({ required String lat1, required String lng1, required String lat2, required String lng2, }) { double distance; double distanceInMeters = Geolocator.distanceBetween( double.parse(lat1), double.parse(lng1), double.parse(lat2), double.parse(lng2), ); if (distanceType == "miles") { distance = distanceInMeters / 1609; } else { distance = distanceInMeters / 1000; } return distance.toStringAsFixed(2); } bool hasValidUrl(String? value) { String pattern = r'(http|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?'; RegExp regExp = RegExp(pattern); if (value == null || value.isEmpty) { return false; } else if (!regExp.hasMatch(value)) { return false; } return true; } static Future uploadUserImageToFireStorage( File image, String filePath, String fileName, ) async { Reference upload = FirebaseStorage.instance.ref().child( '$filePath/$fileName', ); UploadTask uploadTask = upload.putFile(image); var downloadUrl = await (await uploadTask.whenComplete(() {})).ref.getDownloadURL(); return downloadUrl.toString(); } static Future makePhoneCall(String phoneNumber) async { final Uri launchUri = Uri(scheme: 'tel', path: phoneNumber); await launchUrl(launchUri); } Future launchURL(Uri url) async { if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { throw Exception('Could not launch $url'); } } Future getBytesFromAsset(String path, int width) async { ByteData data = await rootBundle.load(path); ui.Codec codec = await ui.instantiateImageCodec( data.buffer.asUint8List(), targetWidth: width, ); ui.FrameInfo fi = await codec.getNextFrame(); return (await fi.image.toByteData( format: ui.ImageByteFormat.png, ))!.buffer.asUint8List(); } static Future selectTime(context) async { FocusScope.of(context).requestFocus(FocusNode()); //remove focus TimeOfDay? newTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); if (newTime != null) { return newTime; } return null; } static Future selectDate(context) async { DateTime? pickedDate = await showDatePicker( context: context, builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: AppThemeData.primary300, // header background color onPrimary: AppThemeData.grey900, // header text color onSurface: AppThemeData.grey900, // body text color ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: AppThemeData.grey900, // button text color ), ), ), child: child!, ); }, initialDate: DateTime.now(), //get today's date firstDate: DateTime(2000), //DateTime.now() - not to allow to choose before today. lastDate: DateTime(2101), ); return pickedDate; } static int calculateDifference(DateTime date) { DateTime now = DateTime.now(); return DateTime( date.year, date.month, date.day, ).difference(DateTime(now.year, now.month, now.day)).inDays; } static String timestampToDate(Timestamp timestamp) { DateTime dateTime = timestamp.toDate(); return DateFormat('MMM dd,yyyy').format(dateTime); } static String timestampToDateTime(Timestamp timestamp) { DateTime dateTime = timestamp.toDate(); return DateFormat('MMM dd,yyyy hh:mm aa').format(dateTime); } static String timestampToDateTime2(Timestamp timestamp) { DateTime dateTime = timestamp.toDate(); return DateFormat('EEE MMM d yyyy').format(dateTime); } static String timestampToTime(Timestamp timestamp) { DateTime dateTime = timestamp.toDate(); return DateFormat('hh:mm aa').format(dateTime); } static String timestampToDateChat(Timestamp timestamp) { DateTime dateTime = timestamp.toDate(); return DateFormat('dd/MM/yyyy').format(dateTime); } static DateTime stringToDate(String openDineTime) { return DateFormat('HH:mm').parse( DateFormat('HH:mm').format( DateFormat("hh:mm a").parse( (Intl.getCurrentLocale() == "en_US") ? openDineTime : openDineTime.toLowerCase(), ), ), ); } static LanguageModel getLanguage() { final String user = Preferences.getString(Preferences.languageCodeKey); Map userMap = jsonDecode(user); return LanguageModel.fromJson(userMap); } static String orderId({String orderId = ''}) { return "#$orderId"; //return "#${(orderId).substring(orderId.length - 10)}"; } static bool isPointInPolygon(LatLng point, List polygon) { int crossings = 0; for (int i = 0; i < polygon.length; i++) { int next = (i + 1) % polygon.length; if (polygon[i].latitude <= point.latitude && polygon[next].latitude > point.latitude || polygon[i].latitude > point.latitude && polygon[next].latitude <= point.latitude) { double edgeLong = polygon[next].longitude - polygon[i].longitude; double edgeLat = polygon[next].latitude - polygon[i].latitude; double interpol = (point.latitude - polygon[i].latitude) / edgeLat; if (point.longitude < polygon[i].longitude + interpol * edgeLong) { crossings++; } } } return (crossings % 2 != 0); } static final smtpServer = SmtpServer( mailSettings!.host.toString(), username: mailSettings!.userName.toString(), password: mailSettings!.password.toString(), port: 465, ignoreBadCertificate: false, ssl: true, allowInsecure: true, ); static Future sendMail({ String? subject, String? body, bool? isAdmin = false, List? recipients, }) async { // Create our message. if (mailSettings != null) { if (isAdmin == true) { recipients!.add(mailSettings!.userName.toString()); } final message = Message() ..from = Address( mailSettings!.userName.toString(), mailSettings!.fromName.toString(), ) ..recipients = recipients! ..subject = subject ..text = body ..html = body; try { final sendReport = await send(message, smtpServer); print('Message sent: $sendReport'); } on MailerException catch (e) { print(e); print('Message not sent.'); for (var p in e.problems) { print('Problem: ${p.code}: ${p.msg}'); } } } // var connection = PersistentConnection(smtpServer); // // // Send the first message // await connection.send(message); } static Uri createCoordinatesUrl( double latitude, double longitude, [ String? label, ]) { Uri uri; if (kIsWeb) { uri = Uri.https('www.google.com', '/maps/search/', { 'api': '1', 'query': '$latitude,$longitude', }); } else if (Platform.isAndroid) { var query = '$latitude,$longitude'; if (label != null) query += '($label)'; uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query}); } else if (Platform.isIOS) { var params = {'ll': '$latitude,$longitude'}; if (label != null) params['q'] = label; uri = Uri.https('maps.apple.com', '/', params); } else { uri = Uri.https('www.google.com', '/maps/search/', { 'api': '1', 'query': '$latitude,$longitude', }); } return uri; } static Future sendOrderEmail({required OrderModel orderModel}) async { EmailTemplateModel? emailTemplateModel = await FireStoreUtils.getEmailTemplates(newOrderPlaced); if (emailTemplateModel != null) { String firstHTML = """ """; String newString = emailTemplateModel.message.toString(); newString = newString.replaceAll( "{username}", "${Constant.userModel!.firstName} ${Constant.userModel!.lastName}", ); newString = newString.replaceAll("{orderid}", orderModel.id.toString()); newString = newString.replaceAll( "{date}", DateFormat('yyyy-MM-dd').format(orderModel.createdAt!.toDate()), ); newString = newString.replaceAll( "{address}", orderModel.address!.getFullAddress(), ); newString = newString.replaceAll( "{paymentmethod}", orderModel.paymentMethod.toString(), ); double deliveryCharge = 0.0; double total = 0.0; double specialDiscount = 0.0; double discount = 0.0; double taxAmount = 0.0; double tipValue = 0.0; String specialLabel = '(${orderModel.specialDiscount!['special_discount_label']}${orderModel.specialDiscount!['specialType'] == "amount" ? currencyModel!.symbol : "%"})'; List htmlList = []; if (orderModel.deliveryCharge != null) { deliveryCharge = double.parse(orderModel.deliveryCharge.toString()); } if (orderModel.tipAmount != null) { tipValue = double.parse(orderModel.tipAmount.toString()); } for (var element in orderModel.products!) { if (element.extrasPrice != null && element.extrasPrice!.isNotEmpty && double.parse(element.extrasPrice!) != 0.0) { total += double.parse(element.quantity.toString()) * double.parse(element.extrasPrice!); } total += double.parse(element.quantity.toString()) * double.parse(element.price.toString()); List? addon = element.extras; String extrasDisVal = ''; for (int i = 0; i < addon!.length; i++) { extrasDisVal += '${addon[i].toString().replaceAll("\"", "")} ${(i == addon.length - 1) ? "" : ","}'; } String product = """ """; htmlList.add(product); } if (orderModel.specialDiscount!.isNotEmpty) { specialDiscount = double.parse( orderModel.specialDiscount!['special_discount'].toString(), ); } if (orderModel.couponId != null && orderModel.couponId!.isNotEmpty) { discount = double.parse(orderModel.discount.toString()); } List taxHtmlList = []; for (var element in taxList) { taxAmount = taxAmount + calculateTax( amount: (total - discount - specialDiscount).toString(), taxModel: element, ); String taxHtml = """${element.title}: ${amountShow(amount: calculateTax(amount: (total - discount - specialDiscount).toString(), taxModel: element).toString())}${taxList.indexOf(element) == taxList.length - 1 ? "" : "
"}"""; taxHtmlList.add(taxHtml); } var totalamount = orderModel.deliveryCharge == null || orderModel.deliveryCharge!.isEmpty ? total + taxAmount - discount - specialDiscount : total + taxAmount + double.parse(orderModel.deliveryCharge!) + double.parse(orderModel.tipAmount!) - discount - specialDiscount; newString = newString.replaceAll( "{subtotal}", amountShow(amount: total.toString()), ); newString = newString.replaceAll( "{coupon}", orderModel.couponId.toString(), ); newString = newString.replaceAll( "{discountamount}", amountShow(amount: orderModel.discount.toString()), ); newString = newString.replaceAll("{specialcoupon}", specialLabel); newString = newString.replaceAll( "{specialdiscountamount}", amountShow(amount: specialDiscount.toString()), ); newString = newString.replaceAll( "{shippingcharge}", amountShow(amount: deliveryCharge.toString()), ); newString = newString.replaceAll( "{tipamount}", amountShow(amount: tipValue.toString()), ); newString = newString.replaceAll( "{totalAmount}", amountShow(amount: totalamount.toString()), ); String tableHTML = htmlList.join(); String lastHTML = "
Product Name
Quantity
Price
Extra Item Price
Total
${element.name} ${element.quantity} ${amountShow(amount: element.price.toString())} ${amountShow(amount: element.extrasPrice.toString())} ${amountShow(amount: ((double.parse(element.quantity.toString()) * double.parse(element.extrasPrice!) + (double.parse(element.quantity.toString()) * double.parse(element.price.toString())))).toString())}
${extrasDisVal.isEmpty ? "" : "Extra Item : $extrasDisVal"}
"; newString = newString.replaceAll( "{productdetails}", firstHTML + tableHTML + lastHTML, ); newString = newString.replaceAll("{taxdetails}", taxHtmlList.join()); newString = newString.replaceAll( "{newwalletbalance}.", amountShow(amount: Constant.userModel!.walletAmount.toString()), ); String subjectNewString = emailTemplateModel.subject.toString(); subjectNewString = subjectNewString.replaceAll( "{orderid}", orderModel.id.toString(), ); await sendMail( subject: subjectNewString, isAdmin: emailTemplateModel.isSendToAdmin, body: newString, recipients: [Constant.userModel!.email], ); } } double calculateDistance(double lat1, double lon1, double lat2, double lon2) { const R = 6371; // Earth's radius in km final dLat = _degToRad(lat2 - lat1); final dLon = _degToRad(lon2 - lon1); final a = sin(dLat / 2) * sin(dLat / 2) + cos(_degToRad(lat1)) * cos(_degToRad(lat2)) * sin(dLon / 2) * sin(dLon / 2); final c = 2 * atan2(sqrt(a), sqrt(1 - a)); return R * c; } double _degToRad(double deg) => deg * (pi / 180); String getTimeInTheMinutes({required double distance}) { double averageSpeed = 40.0; double estimatedTime = (distance / averageSpeed) * 60; return "${estimatedTime.toStringAsFixed(2)} minutes"; } /// Calculate tax amount for a single tax model static double getTaxValue({ required String amount, required TaxModel taxModel, }) { double taxVal = 0.0; if (taxModel.enable == true) { if (taxModel.type == "fix") { taxVal = double.tryParse(taxModel.tax.toString()) ?? 0.0; } else { taxVal = (double.tryParse(amount) ?? 0.0) * (double.tryParse(taxModel.tax.toString()) ?? 0.0) / 100; } } return taxVal; } Future getBytesFromUrl(String url, {int width = 100}) async { try { final http.Response response = await http.get(Uri.parse(url)); if (response.statusCode != 200) throw Exception("Failed to load image"); final Uint8List bytes = response.bodyBytes; final ui.Codec codec = await ui.instantiateImageCodec( bytes, targetWidth: width, ); final ui.FrameInfo frameInfo = await codec.getNextFrame(); final ByteData? byteData = await frameInfo.image.toByteData( format: ui.ImageByteFormat.png, ); return byteData!.buffer.asUint8List(); } catch (e) { print("⚠️ getBytesFromUrl error: $e — using default cab icon"); final ByteData data = await rootBundle.load('assets/images/ic_cab.png'); return data.buffer.asUint8List(); } } // Future getBytesFromUrl(String url, {int width = 100}) async { // final http.Response response = await http.get(Uri.parse(url)); // if (response.statusCode != 200) { // throw Exception("Failed to load image from $url"); // } // // final Uint8List bytes = response.bodyBytes; // // // Decode & resize // final ui.Codec codec = await ui.instantiateImageCodec(bytes, targetWidth: width); // final ui.FrameInfo frameInfo = await codec.getNextFrame(); // // final ByteData? byteData = await frameInfo.image.toByteData(format: ui.ImageByteFormat.png); // return byteData!.buffer.asUint8List(); // } } extension StringExtension on String { String capitalizeString() { return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; } }