Files
Fondex/lib/constant/constant.dart

995 lines
32 KiB
Dart

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<CartProductModel> cartItem = <CartProductModel>[].obs;
class Constant {
static const userPlaceHolder = "assets/images/user_placeholder.png";
static String senderId = '';
static String jsonNotificationFileURL = '';
static String appVersion = '';
static List<TaxModel> 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<ZoneModel> 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<VendorModel>? 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<void> 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<void> 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<ThemeController>();
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.,@?^=%&amp;:/~+#-]*[\w@?^=%&amp;/~+#-])?';
RegExp regExp = RegExp(pattern);
if (value == null || value.isEmpty) {
return false;
} else if (!regExp.hasMatch(value)) {
return false;
}
return true;
}
static Future<String> 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<void> makePhoneCall(String phoneNumber) async {
final Uri launchUri = Uri(scheme: 'tel', path: phoneNumber);
await launchUrl(launchUri);
}
Future<void> launchURL(Uri url) async {
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
}
Future<Uint8List> 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<TimeOfDay?> 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<DateTime?> 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<String, dynamic> 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<GeoPoint> 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<void> sendMail({
String? subject,
String? body,
bool? isAdmin = false,
List<dynamic>? 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<void> sendOrderEmail({required OrderModel orderModel}) async {
EmailTemplateModel? emailTemplateModel =
await FireStoreUtils.getEmailTemplates(newOrderPlaced);
if (emailTemplateModel != null) {
String firstHTML = """
<table style="width: 100%; border-collapse: collapse; border: 1px solid rgb(0, 0, 0);">
<thead>
<tr>
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Product Name<br></th>
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Quantity<br></th>
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Price<br></th>
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Extra Item Price<br></th>
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Total<br></th>
</tr>
</thead>
<tbody>
""";
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<String> 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<dynamic>? addon = element.extras;
String extrasDisVal = '';
for (int i = 0; i < addon!.length; i++) {
extrasDisVal +=
'${addon[i].toString().replaceAll("\"", "")} ${(i == addon.length - 1) ? "" : ","}';
}
String product = """
<tr>
<td style="width: 20%; border-top: 1px solid rgb(0, 0, 0);">${element.name}</td>
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${element.quantity}</td>
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: element.price.toString())}</td>
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: element.extrasPrice.toString())}</td>
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: ((double.parse(element.quantity.toString()) * double.parse(element.extrasPrice!) + (double.parse(element.quantity.toString()) * double.parse(element.price.toString())))).toString())}</td>
</tr>
<tr>
<td style="width: 20%;">${extrasDisVal.isEmpty ? "" : "Extra Item : $extrasDisVal"}</td>
</tr>
""";
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<String> taxHtmlList = [];
for (var element in taxList) {
taxAmount =
taxAmount +
calculateTax(
amount: (total - discount - specialDiscount).toString(),
taxModel: element,
);
String taxHtml =
"""<span style="font-size: 1rem;">${element.title}: ${amountShow(amount: calculateTax(amount: (total - discount - specialDiscount).toString(), taxModel: element).toString())}${taxList.indexOf(element) == taxList.length - 1 ? "</span>" : "<br></span>"}""";
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 = "</tbody></table>";
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<Uint8List> 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<Uint8List> 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()}";
}
}