INFRA: Set Up Project.

This commit is contained in:
2025-11-28 11:10:49 +05:00
commit c798279f7d
609 changed files with 77436 additions and 0 deletions

21
lib/constant/assets.dart Normal file
View File

@@ -0,0 +1,21 @@
class AppAssets {
static const assetFromImagesPath = 'assets/images/';
static const assetFromIconsPath = 'assets/icons/';
//images
static const onBoardingBG = '${assetFromImagesPath}onboarding_bg.png';
static const imgOnBoarding = '${assetFromImagesPath}img_onboarding.png';
//icons
static const icAppLogo = '${assetFromIconsPath}app_logo.png';
static const icArrowLeft = '${assetFromIconsPath}ic_arrow_left.png';
static const icMessage = '${assetFromIconsPath}ic_message.png';
static const icIndia = '${assetFromIconsPath}ic_india.png';
static const icArrowsClockwise = '${assetFromIconsPath}ic_arrows_clockwise.png';
static const icLocation = '${assetFromIconsPath}ic_location.png';
static const icPickup = '${assetFromIconsPath}ic_pickup.png';
static const icPlus = '${assetFromIconsPath}plus.svg';
}

View File

@@ -0,0 +1,61 @@
class CollectionName {
static const String users = "users";
static const String zone = "zone";
static const String onBoarding = "on_boarding";
static const String referral = "referral";
static const String sections = "sections";
static const String bookedTable = "booked_table";
static const String chatDriver = "chat_driver";
static const String chatStore = "chat_store";
static const String coupons = "coupons";
static const String currencies = "currencies";
static const String documents = "documents";
static const String documentsVerify = "documents_verify";
static const String driverPayouts = "driver_payouts";
static const String dynamicNotification = "dynamic_notification";
static const String emailTemplates = "email_templates";
static const String favoriteItem = "favorite_item";
static const String favoriteVendor = "favorite_vendor";
static const String giftCards = "gift_cards";
static const String giftPurchases = "gift_purchases";
static const String bannerItems = "banner_items";
static const String notifications = "notifications";
static const String payouts = "payouts";
static const String vendorOrders = "vendor_orders";
static const String reviewAttributes = "review_attributes";
static const String settings = "settings";
static const String story = "story";
static const String tax = "tax";
static const String vendorAttributes = "vendor_attributes";
static const String vendorCategories = "vendor_categories";
static const String vendorProducts = "vendor_products";
static const String vendors = "vendors";
static const String wallet = "wallet";
static const String withdrawMethod = "withdraw_method";
static const String advertisements = "advertisements";
static const String cashback = "cashback";
static const String cashbackRedeem = "cashback_redeem";
static const String currency = 'currencies';
static const String brands = 'brands';
static const String parcelCategory = 'parcel_categories';
static const String parcelWeight = 'parcel_weight';
static const String parcelOrders = "parcel_orders";
static const String vehicleType = 'vehicle_type';
static const String rides = 'rides';
static const String popularDestinations = 'popular_destinations';
static const String providerCategories = 'provider_categories';
static const String providersServices = 'providers_services';
static const String favoriteService = 'favorite_service';
static const String itemsReview = 'items_review';
static const String providersCoupons = 'providers_coupons';
static const String providerOrders = 'provider_orders';
static const String providersWorkers = 'providers_workers';
static const String promos = 'promos';
static const String parcelCoupons = 'parcel_coupons';
static const String rentalVehicleType = 'rental_vehicle_type';
static const String rentalPackages = 'rental_packages';
static const String rentalCoupons = 'rental_coupons';
static const String rentalOrders = 'rental_orders';
static const String sos = 'SOS';
static const String complaints = 'complaints';
}

779
lib/constant/constant.dart Normal file
View File

@@ -0,0 +1,779 @@
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';
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()}";
}
}

View File

@@ -0,0 +1,932 @@
import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import '../../models/onprovider_order_model.dart';
import '../models/wallet_transaction_model.dart';
import '../payment/xenditModel.dart';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as maths;
import 'package:flutter/material.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:uuid/uuid.dart';
import '../constant/constant.dart';
import '../models/payment_model/cod_setting_model.dart';
import '../models/payment_model/flutter_wave_model.dart';
import '../models/payment_model/mercado_pago_model.dart';
import '../models/payment_model/mid_trans.dart';
import '../models/payment_model/orange_money.dart';
import '../models/payment_model/pay_fast_model.dart';
import '../models/payment_model/pay_stack_model.dart';
import '../models/payment_model/paypal_model.dart';
import '../models/payment_model/paytm_model.dart';
import '../models/payment_model/razorpay_model.dart';
import '../models/payment_model/stripe_model.dart';
import '../models/payment_model/wallet_setting_model.dart';
import '../models/payment_model/xendit.dart';
import '../payment/MercadoPagoScreen.dart';
import '../payment/PayFastScreen.dart';
import '../payment/getPaytmTxtToken.dart';
import '../payment/midtrans_screen.dart';
import '../payment/orangePayScreen.dart';
import '../payment/paystack/pay_stack_screen.dart';
import '../payment/paystack/pay_stack_url_model.dart';
import '../payment/paystack/paystack_url_genrater.dart';
import '../payment/stripe_failed_model.dart';
import '../payment/xenditScreen.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
import '../service/fire_store_utils.dart';
import '../service/send_notification.dart';
import '../themes/app_them_data.dart';
import '../themes/show_toast_dialog.dart';
import '../utils/preferences.dart';
import 'on_demand_dashboard_controller.dart';
class OnDemandPaymentController extends GetxController {
Rx<OnProviderOrderModel?> onDemandOrderModel = Rx<OnProviderOrderModel?>(null);
RxDouble totalAmount = 0.0.obs;
late bool isExtra;
RxBool isLoading = false.obs;
RxString selectedPaymentMethod = ''.obs;
RxBool isOrderPlaced = false.obs;
@override
void onInit() {
super.onInit();
isLoading.value = true;
final args = Get.arguments as Map<String, dynamic>;
onDemandOrderModel = args['onDemandOrderModel'];
totalAmount = (args['totalAmount'] as double).obs;
print("payment totalAmount ::::::::: $totalAmount");
isExtra = args['isExtra'];
getPaymentSettings();
}
Future<void> placeOrder() async {
if (!isExtra) {
// Normal Order
ShowToastDialog.showLoader("Please wait...".tr);
onDemandOrderModel.value?.payment_method = selectedPaymentMethod.value;
onDemandOrderModel.value?.paymentStatus = onDemandOrderModel.value?.provider.priceUnit == "Fixed" && selectedPaymentMethod.value == "cod" ? false : true;
onDemandOrderModel.value?.extraPaymentStatus = true;
await FireStoreUtils.onDemandOrderPlace(onDemandOrderModel.value!, totalAmount.value);
if (onDemandOrderModel.value?.status == Constant.orderPlaced) {
await FireStoreUtils.sendOrderOnDemandServiceEmail(orderModel: onDemandOrderModel.value!);
final providerUser = await FireStoreUtils.getUserProfile(onDemandOrderModel.value!.provider.author!);
if (providerUser != null) {
final payLoad = {"type": 'provider_order', "orderId": onDemandOrderModel.value?.id};
await SendNotification.sendFcmMessage(Constant.bookingPlaced, providerUser.fcmToken ?? '', payLoad);
}
ShowToastDialog.showToast("OnDemand Service successfully booked".tr);
}
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.value.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: onDemandOrderModel.value!.id,
note: "Booking Amount debited".tr,
paymentStatus: "success".tr,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
}
});
}
ShowToastDialog.closeLoader();
Get.offAll(const OnDemandDashboardScreen());
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
controller.selectedIndex.value = 2;
} else {
// Extra Charges Flow
onDemandOrderModel.value?.createdAt = Timestamp.now();
onDemandOrderModel.value?.extraPaymentStatus = true;
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.value.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: onDemandOrderModel.value!.id,
note: "Booking Extra charge debited",
paymentStatus: "success".tr,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
}
});
}
// Handle wallet payment if needed
if (selectedPaymentMethod.value != 'cod') {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
serviceType: 'ondemand-service',
amount: totalAmount.value,
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "provider",
userId: onDemandOrderModel.value?.provider.author!,
isTopup: true,
orderId: onDemandOrderModel.value?.id,
note: 'Extra Charge Amount Credited',
paymentStatus: "success".tr,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-$totalAmount", userId: FireStoreUtils.getCurrentUid());
}
});
}
await FireStoreUtils.updateOnDemandOrder(onDemandOrderModel.value!);
ShowToastDialog.closeLoader();
Get.offAll(const OnDemandDashboardScreen());
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
controller.selectedIndex.value = 2;
}
}
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
isLoading.value = true;
await FireStoreUtils.getPaymentSettingsData().then((value) {
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.cod.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
} else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'eMart Customer';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
isLoading.value = false;
});
}
// Strip
Future<void> stripeMakePayment({required String amount}) async {
log(double.parse(amount).toStringAsFixed(0));
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
log("stripe Responce====>$paymentIntentData");
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
merchantDisplayName: 'GoRide',
),
);
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
log("$e \n$s");
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": Constant.userModel?.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
);
return jsonDecode(response.body);
} catch (e) {
log(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
},
],
"payer": {"email": Constant.userModel?.email},
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
"auto_return": "approved",
// Automatically return after payment is approved
});
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Error creating preference: ${response.body}');
return null;
}
}
//Paypal
void paypalPaymentSheet(String amount, context) {
Navigator.of(context).push(
MaterialPageRoute(
builder:
(BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.parkme://paypalpay",
cancelURL: "com.parkme://paypalpay",
transactions: [
{
"amount": {
"total": amount,
"currency": "USD",
"details": {"subtotal": amount},
},
},
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
placeOrder();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
),
),
);
}
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
await PayStackURLGen.payStackURLGen(
amount: (double.parse(totalAmount) * 100).toString(),
currency: "ZAR",
secretKey: payStackModel.value.secretKey.toString(),
userModel: Constant.userModel!,
).then((value) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(
PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
),
)!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
//flutter wave Payment Method
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {"email": Constant.userModel?.email.toString(), "phonenumber": Constant.userModel?.phoneNumber, "name": Constant.userModel?.fullName()},
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Payment initialization failed: ${response.body}');
return null;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
///Paytm payment function
Future<void> getPaytmCheckSum(context, {required double amount}) async {
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
);
final data = jsonDecode(response.body);
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
initiatePayment(amount: amount, orderId: orderId).then((value) {
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
GetPaymentTxtTokenModel result = value;
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
});
});
}
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
// try {
// var response = AllInOneSdk.startTransaction(
// paytmModel.value.paytmMID.toString(),
// orderId,
// amount.toString(),
// txnTokenBy,
// callBackURL,
// isStaging,
// true,
// true,
// );
//
// response.then((value) {
// if (value!["RESPMSG"] == "Txn Success") {
// print("txt done!!");
// ShowToastDialog.showToast("Payment Successful!!");
// placeOrder();
// }
// }).catchError((onError) {
// if (onError is PlatformException) {
// Get.back();
//
// ShowToastDialog.showToast(onError.message.toString());
// } else {
// log("======>>2");
// Get.back();
// ShowToastDialog.showToast(onError.message.toString());
// }
// });
// } catch (err) {
// Get.back();
// ShowToastDialog.showToast(err.toString());
// }
}
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
);
final data = jsonDecode(response.body);
return data['status'];
}
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
final response = await http.post(
Uri.parse(initiateURL),
headers: {},
body: {
"mid": paytmModel.value.paytmMID,
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
"amount": amount.toString(),
"currency": "INR",
"callback_url": callback,
"custId": FireStoreUtils.getCurrentUid(),
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
},
);
log(response.body);
final data = jsonDecode(response.body);
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
Get.back();
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
}
return GetPaymentTxtTokenModel.fromJson(data);
}
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {'contact': Constant.userModel?.phoneNumber, 'email': Constant.userModel?.email},
'external': {
'wallets': ['paytm'],
},
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
final response = await http.post(
url,
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
body: jsonEncode({
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
///Orangepay payment
// static variables to store transaction session
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString().isNotEmpty) {
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
}
Future<String> fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
String apiUrl = 'https://api.orange.com/oauth/v3/token';
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth ?? ''}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
body: requestBody,
);
if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'] ?? '';
if (accessToken.isEmpty) {
ShowToastDialog.showToast("Failed to get access token".tr);
return '';
}
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future<String> webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
orderId = orderIdData;
amount = amountData;
// ✅ Null-safe handling
bool isSandbox = orangeMoneyModel.value.isSandbox ?? false;
String apiUrl = isSandbox ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": isSandbox ? "OUV" : currency,
"order_id": orderId,
"amount": amount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl ?? "",
"cancel_url": orangeMoneyModel.value.cancelUrl ?? "",
"notif_url": orangeMoneyModel.value.notifUrl ?? "",
};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
if (response.statusCode == 201) {
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'] ?? '';
return responseData['payment_url'] ?? '';
} else {
return '';
}
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
orderId = '';
amount = '';
}
// static String accessToken = '';
// static String payToken = '';
// static String orderId = '';
// static String amount = '';
//
// Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
// reset();
// var id = const Uuid().v4();
// var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
// ShowToastDialog.closeLoader();
// if (paymentURL.toString() != '') {
// Get.to(
// () => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken),
// )!.then((value) {
// if (value == true) {
// ShowToastDialog.showToast("Payment Successful!!".tr);
// placeOrder();
// ();
// }
// });
// } else {
// ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
// }
// }
//
// Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
// String apiUrl = 'https://api.orange.com/oauth/v3/token';
// Map<String, String> requestBody = {'grant_type': 'client_credentials'};
//
// var response = await http.post(
// Uri.parse(apiUrl),
// headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
// body: requestBody,
// );
//
// // Handle the response
//
// if (response.statusCode == 200) {
// Map<String, dynamic> responseData = jsonDecode(response.body);
//
// accessToken = responseData['access_token'];
// // ignore: use_build_context_synchronously
// return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
// } else {
// ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
// return '';
// }
// }
//
// Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
// orderId = orderIdData;
// amount = amountData;
// String apiUrl =
// orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
// Map<String, String> requestBody = {
// "merchant_key": orangeMoneyModel.value.merchantKey ?? '',
// "currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
// "order_id": orderId,
// "amount": amount,
// "reference": 'Y-Note Test',
// "lang": "en",
// "return_url": orangeMoneyModel.value.returnUrl ?? "",
// "cancel_url": orangeMoneyModel.value.cancelUrl ?? "",
// "notif_url": orangeMoneyModel.value.notifUrl ?? "",
// // "return_url": orangeMoneyModel.value.returnUrl!.toString(),
// // "cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
// // "notif_url": orangeMoneyModel.value.notifUrl!.toString(),
// };
//
// var response = await http.post(
// Uri.parse(apiUrl),
// headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
// body: json.encode(requestBody),
// );
//
// // Handle the response
// if (response.statusCode == 201) {
// Map<String, dynamic> responseData = jsonDecode(response.body);
// if (responseData['message'] == 'OK') {
// payToken = responseData['pay_token'];
// return responseData['payment_url'];
// } else {
// return '';
// }
// } else {
// ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
// return '';
// }
// }
//
// static void reset() {
// accessToken = '';
// payToken = '';
// orderId = '';
// amount = '';
// }
///XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
import 'package:customer/models/user_model.dart';
import 'package:get/get.dart';
import '../constant/constant.dart';
import '../service/fire_store_utils.dart';
class AddressListController extends GetxController {
Rx<UserModel> userModel = UserModel().obs;
RxList<ShippingAddress> shippingAddressList = <ShippingAddress>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getUser();
super.onInit();
}
Future<void> getUser() async {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
if (value != null) {
userModel.value = value;
if (userModel.value.shippingAddress != null) {
shippingAddressList.value = userModel.value.shippingAddress!;
}
}
});
isLoading.value = false;
}
Future<void> deleteAddress(int index) async {
if (shippingAddressList.isNotEmpty && index < shippingAddressList.length) {
shippingAddressList.removeAt(index);
userModel.value.shippingAddress = shippingAddressList;
if (shippingAddressList.isNotEmpty) {
Constant.selectedLocation = shippingAddressList.first;
}
await FireStoreUtils.updateUser(userModel.value);
shippingAddressList.refresh();
}
}
}

View File

@@ -0,0 +1,48 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/advertisement_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class AdvertisementListController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
getAdvertisementList();
getFavouriteRestaurant();
super.onInit();
}
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
Future<void> getAdvertisementList() async {
advertisementList.clear();
List<VendorModel> allNearestRestaurant = <VendorModel>[];
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
allNearestRestaurant.addAll(event);
await FireStoreUtils.getAllAdvertisement().then((value) {
List<AdvertisementModel> adsList = value;
advertisementList.addAll(
adsList.where(
(ads) => allNearestRestaurant.any(
(restaurant) => restaurant.id == ads.vendorId,
),
),
);
});
isLoading.value = false;
});
}
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
Future<void> getFavouriteRestaurant() async {
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
}
}
}

View File

@@ -0,0 +1,58 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/brands_model.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class AllBrandProductController extends GetxController {
RxList<ProductModel> productList = <ProductModel>[].obs;
Rx<BrandsModel> brandModel = BrandsModel().obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArguments();
super.onInit();
}
Future<void> getArguments() async {
final arguments = Get.arguments;
if (arguments != null) {
brandModel.value = arguments['brandModel'];
await getProductByCategoryId();
}
isLoading.value = false;
}
Future<void> getProductByCategoryId() async {
List<ProductModel> productDataList = await FireStoreUtils.getProductListByBrandId(brandModel.value.id.toString());
List<VendorModel> vendorList = await FireStoreUtils.getAllStoresFuture();
List<ProductModel> allProduct = <ProductModel>[];
for (var vendor in vendorList) {
await FireStoreUtils.getAllProducts(vendor.id.toString()).then((value) {
if (Constant.isSubscriptionModelApplied == true || vendor.adminCommission?.isEnabled == true) {
if (vendor.subscriptionPlan != null && Constant.isExpire(vendor) == false) {
if (vendor.subscriptionPlan?.itemLimit == '-1') {
allProduct.addAll(value);
} else {
int selectedProduct =
value.length < int.parse(vendor.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(vendor.subscriptionPlan?.itemLimit ?? '0');
allProduct.addAll(value.sublist(0, selectedProduct));
}
}
} else {
allProduct.addAll(value);
}
});
}
for (var element in productDataList) {
final bool productIsInList = allProduct.any((product) => product.id == element.id);
if (productIsInList) {
productList.add(element);
}
}
}
}

View File

@@ -0,0 +1,30 @@
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class AllCategoryProductController extends GetxController {
RxBool isLoading = true.obs;
Rx<VendorCategoryModel> categoryModel = VendorCategoryModel().obs;
RxList<ProductModel> productList = <ProductModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getArguments();
super.onInit();
}
Future<void> getArguments() async {
final arguments = Get.arguments;
if (arguments != null) {
categoryModel.value = arguments['categoryModel'];
await getProductByCategoryId();
}
isLoading.value = false;
}
Future<void> getProductByCategoryId() async {
productList.value = await FireStoreUtils.getProductListByCategoryId(categoryModel.value.id.toString());
}
}

View File

@@ -0,0 +1,340 @@
import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/widget/geoflutterfire/src/geoflutterfire.dart';
import 'package:dropdown_textfield/dropdown_textfield.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as latlong;
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import '../constant/constant.dart';
import '../models/parcel_category.dart';
import '../models/parcel_order_model.dart';
import '../models/parcel_weight_model.dart';
import '../models/user_model.dart';
import '../screen_ui/parcel_service/parcel_order_confirmation.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
class BookParcelController extends GetxController {
// Sender details
final Rx<TextEditingController> senderLocationController = TextEditingController().obs;
final Rx<TextEditingController> senderNameController = TextEditingController().obs;
final Rx<TextEditingController> senderMobileController = TextEditingController().obs;
final Rx<SingleValueDropDownController> senderWeightController = SingleValueDropDownController().obs;
final Rx<TextEditingController> senderNoteController = TextEditingController().obs;
final Rx<TextEditingController> senderCountryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
// Receiver details
final Rx<TextEditingController> receiverLocationController = TextEditingController().obs;
final Rx<TextEditingController> receiverNameController = TextEditingController().obs;
final Rx<TextEditingController> receiverMobileController = TextEditingController().obs;
final Rx<TextEditingController> receiverNoteController = TextEditingController().obs;
final Rx<TextEditingController> receiverCountryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
// Delivery type
final RxString selectedDeliveryType = 'now'.obs;
// Scheduled delivery fields
final Rx<TextEditingController> scheduledDateController = TextEditingController().obs;
final Rx<TextEditingController> scheduledTimeController = TextEditingController().obs;
final RxString scheduledDate = ''.obs;
final RxString scheduledTime = ''.obs;
// Parcel weight list
final RxList<ParcelWeightModel> parcelWeight = <ParcelWeightModel>[].obs;
final RxList<XFile> images = <XFile>[].obs;
final ImagePicker _picker = ImagePicker();
Rx<UserLocation?> senderLocation = Rx<UserLocation?>(null);
Rx<UserLocation?> receiverLocation = Rx<UserLocation?>(null);
ParcelWeightModel? selectedWeight;
ParcelCategory? selectedCategory;
// UI observables
RxBool isScheduled = false.obs;
RxDouble distance = 0.0.obs;
RxDouble duration = 0.0.obs;
RxDouble subTotal = 0.0.obs;
@override
void onInit() {
super.onInit();
setArguments();
getParcelWeight();
setCurrentLocationForSenderAndReceiver();
}
void setArguments() {
if (Get.arguments != null && Get.arguments['parcelCategory'] != null) {
selectedCategory = Get.arguments['parcelCategory'];
}
}
Future<void> getParcelWeight() async {
parcelWeight.value = await FireStoreUtils.getParcelWeight();
}
Future<void> pickScheduledDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime.now().add(const Duration(days: 365)));
if (picked != null) {
final formattedDate = "${picked.day}/${picked.month}/${picked.year}";
scheduledDate.value = formattedDate;
scheduledDateController.value.text = formattedDate;
}
}
Future<void> pickScheduledTime(BuildContext context) async {
final TimeOfDay? picked = await showTimePicker(context: context, initialTime: TimeOfDay.now());
if (picked != null) {
final formattedTime = picked.format(context);
scheduledTime.value = formattedTime;
scheduledTimeController.value.text = formattedTime;
}
}
void onCameraClick(BuildContext context) {
final action = CupertinoActionSheet(
message: Text('Add your parcel image.'.tr, style: const TextStyle(fontSize: 15.0)),
actions: <Widget>[
CupertinoActionSheetAction(
child: Text('Choose image from gallery'.tr),
onPressed: () async {
Navigator.pop(context);
final imageList = await _picker.pickMultiImage();
if (imageList.isNotEmpty) {
images.addAll(imageList);
}
},
),
CupertinoActionSheetAction(
child: Text('Take a picture'.tr),
onPressed: () async {
Navigator.pop(context);
final XFile? photo = await _picker.pickImage(source: ImageSource.camera);
if (photo != null) {
images.add(photo);
}
},
),
],
cancelButton: CupertinoActionSheetAction(child: Text('Cancel'.tr), onPressed: () => Navigator.pop(context)),
);
showCupertinoModalPopup(context: context, builder: (context) => action);
}
Future<void> setCurrentLocationForSenderAndReceiver() async {
try {
await Geolocator.requestPermission();
final position = await Geolocator.getCurrentPosition();
final placemarks = await placemarkFromCoordinates(position.latitude, position.longitude);
final place = placemarks.first;
final address = "${place.name}, ${place.subLocality}, ${place.locality}, ${place.administrativeArea}, ${place.postalCode}, ${place.country}";
final userLocation = UserLocation(latitude: position.latitude, longitude: position.longitude);
senderLocation.value = userLocation;
senderLocationController.value.text = address;
} catch (e) {
debugPrint("Failed to fetch current location: $e");
}
}
bool validateFields() {
if (senderNameController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter sender name".tr);
return false;
} else if (senderMobileController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter sender mobile".tr);
return false;
} else if (senderLocationController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter sender address".tr);
return false;
} else if (receiverNameController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter receiver name".tr);
return false;
} else if (receiverMobileController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter receiver mobile".tr);
return false;
} else if (receiverLocationController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter receiver address".tr);
return false;
} else if (isScheduled.value) {
if (scheduledDate.value.isEmpty) {
ShowToastDialog.showToast("Please select scheduled date".tr);
return false;
} else if (scheduledTime.value.isEmpty) {
ShowToastDialog.showToast("Please select scheduled time".tr);
return false;
}
}
if (selectedWeight == null) {
ShowToastDialog.showToast("Please select parcel weight".tr);
return false;
} else if (senderLocation.value == null || receiverLocation.value == null) {
ShowToastDialog.showToast("Please select both sender and receiver locations".tr);
return false;
}
return true;
}
Future<void> bookNow() async {
if (!validateFields()) return;
try {
distance.value = 0.0;
if (Constant.selectedMapType == 'osm') {
print("Fetching route using OSM");
print("Sender Location: ${senderLocation.value?.latitude}, ${senderLocation.value?.longitude}");
print("Receiver Location: ${receiverLocation.value?.latitude}, ${receiverLocation.value?.longitude}");
await fetchRouteWithWaypoints([
latlong.LatLng(senderLocation.value?.latitude ?? 0.0, senderLocation.value?.longitude ?? 0.0),
latlong.LatLng(receiverLocation.value?.latitude ?? 0.0, receiverLocation.value?.longitude ?? 0.0),
]);
} else {
await fetchGoogleRouteWithWaypoints();
}
if (distance.value < 0.5) {
ShowToastDialog.showToast("Sender's location to receiver's location should be more than 1 km.".tr);
return;
}
subTotal.value = (distance.value * double.parse(selectedWeight!.deliveryCharge.toString()));
goToCart();
} catch (e) {
ShowToastDialog.showToast("Something went wrong while booking.".tr);
debugPrint("bookNow error: $e");
}
}
void goToCart() {
DateTime senderPickup = isScheduled.value ? parseScheduledDateTime(scheduledDate.value, scheduledTime.value) : DateTime.now();
print("Sender Pickup: $distance");
ParcelOrderModel order = ParcelOrderModel(
id: Constant.getUuid(),
subTotal: subTotal.value.toString(),
parcelType: selectedCategory?.title ?? '',
parcelCategoryID: selectedCategory?.id ?? '',
note: senderNoteController.value.text,
receiverNote: receiverNoteController.value.text,
distance: distance.value.toStringAsFixed(4),
parcelWeight: selectedWeight?.title ?? '',
parcelWeightCharge: selectedWeight?.deliveryCharge,
sendToDriver: isScheduled.value == true ? false : true,
senderPickupDateTime: Timestamp.fromDate(senderPickup),
receiverPickupDateTime: Timestamp.fromDate(DateTime.now()),
taxSetting: Constant.taxList,
isSchedule: isScheduled.value,
sourcePoint: G(
geopoint: GeoPoint(senderLocation.value!.latitude ?? 0.0, senderLocation.value!.longitude ?? 0.0),
geohash: Geoflutterfire().point(latitude: senderLocation.value!.latitude ?? 0.0, longitude: senderLocation.value!.longitude ?? 0.0).hash,
),
destinationPoint: G(
geopoint: GeoPoint(receiverLocation.value!.latitude ?? 0.0, receiverLocation.value!.longitude ?? 0.0),
geohash: Geoflutterfire().point(latitude: receiverLocation.value!.latitude ?? 0.0, longitude: receiverLocation.value!.longitude ?? 0.0).hash,
),
sender: LocationInformation(
address: senderLocationController.value.text,
name: senderNameController.value.text,
phone: "(${senderCountryCodeController.value.text}) ${senderMobileController.value.text}",
),
receiver: LocationInformation(
address: receiverLocationController.value.text,
name: receiverNameController.value.text,
phone: "(${receiverCountryCodeController.value.text}) ${receiverMobileController.value.text}",
),
receiverLatLong: receiverLocation.value,
senderLatLong: senderLocation.value,
sectionId: Constant.sectionConstantModel?.id ?? '',
);
debugPrint("Order Distance: ${distance.value}");
debugPrint("Subtotal: ${subTotal.value}");
debugPrint("Order JSON: ${order.toJson()}");
Get.to(() => ParcelOrderConfirmationScreen(), arguments: {'parcelOrder': order, 'images': images});
}
DateTime parseScheduledDateTime(String dateStr, String timeStr) {
try {
final dateParts = dateStr.split('/');
final day = int.parse(dateParts[0]);
final month = int.parse(dateParts[1]);
final year = int.parse(dateParts[2]);
final time = TimeOfDay(hour: int.parse(timeStr.split(':')[0]), minute: int.parse(timeStr.split(':')[1].split(' ')[0]));
final isPM = timeStr.toLowerCase().contains('pm');
final hour24 = isPM && time.hour < 12 ? time.hour + 12 : time.hour;
return DateTime(year, month, day, hour24, time.minute);
} catch (e) {
debugPrint("Failed to parse scheduled date/time: $e");
return DateTime.now();
}
}
Future<void> fetchGoogleRouteWithWaypoints() async {
final origin = '${senderLocation.value!.latitude},${senderLocation.value!.longitude}';
final destination = '${receiverLocation.value!.latitude},${receiverLocation.value!.longitude}';
final url = Uri.parse('https://maps.googleapis.com/maps/api/directions/json?origin=$origin&destination=$destination&mode=driving&key=${Constant.mapAPIKey}');
try {
final response = await http.get(url);
final data = json.decode(response.body);
if (data['status'] == 'OK') {
final route = data['routes'][0];
final legs = route['legs'] as List;
num totalDistance = 0;
num totalDuration = 0;
for (var leg in legs) {
totalDistance += leg['distance']['value'];
totalDuration += leg['duration']['value'];
}
if (Constant.distanceType.toLowerCase() == "KM".toLowerCase()) {
distance.value = totalDistance / 1000.0;
} else {
distance.value = totalDistance / 1609.34;
}
duration.value = (totalDuration / 60).round().toDouble();
} else {
debugPrint('Google Directions API Error: ${data['status']}');
}
} catch (e) {
debugPrint("Google route fetch error: $e");
}
}
Future<void> fetchRouteWithWaypoints(List<latlong.LatLng> points) async {
final coordinates = points.map((p) => '${p.longitude},${p.latitude}').join(';');
final url = Uri.parse('https://router.project-osrm.org/route/v1/driving/$coordinates?overview=full&geometries=geojson');
try {
final response = await http.get(url);
if (response.statusCode == 200) {
final decoded = json.decode(response.body);
final dist = decoded['routes'][0]['distance'];
final dur = decoded['routes'][0]['duration'];
if (Constant.distanceType.toLowerCase() == "KM".toLowerCase()) {
distance.value = dist / 1000.00;
} else {
distance.value = dist / 1609.34;
}
duration.value = (dur / 60).round().toDouble();
} else {
debugPrint("Failed to get route: ${response.body}");
}
} catch (e) {
debugPrint("Route fetch error: $e");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
import 'package:customer/models/coupon_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class CabCouponCodeController extends GetxController {
// Add your methods and properties here
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
void getData(){
getCouponCode();
}
RxBool isLoading = true.obs;
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
Future<void> getCouponCode() async {
await FireStoreUtils.getCabCoupon().then((value) {
cabCouponList.value = value;
// Handle the retrieved coupon code
});
print("cabCouponList ${cabCouponList.length}");
isLoading.value = false;
}
}

View File

@@ -0,0 +1,33 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/screen_ui/cab_service_screens/cab_home_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
import '../screen_ui/cab_service_screens/my_cab_booking_screen.dart';
class CabDashboardController extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
// TODO: implement onInit
getTaxList();
if (Constant.walletSetting == false) {
pageList.value = [CabHomeScreen(), const MyCabBookingScreen(), const ProfileScreen()];
} else {
pageList.value = [CabHomeScreen(), const MyCabBookingScreen(), const WalletScreen(), const ProfileScreen()];
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
}

View File

@@ -0,0 +1,22 @@
import 'package:customer/models/banner_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class CabHomeController extends GetxController {
RxBool isLoading = true.obs;
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
Future<void> getData() async {
await FireStoreUtils.getHomeTopBanner().then((value) {
bannerTopHome.value = value;
});
isLoading.value = false;
}
}

View File

@@ -0,0 +1,138 @@
import 'dart:convert';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/rating_model.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:google_maps_flutter/google_maps_flutter.dart' as gmap;
import 'package:latlong2/latlong.dart' as osm;
import '../models/cab_order_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
import '../themes/app_them_data.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
class CabOrderDetailsController extends GetxController {
Rx<CabOrderModel> cabOrder = CabOrderModel().obs;
RxBool isLoading = false.obs;
// Google Maps Data
RxSet<gmap.Marker> googleMarkers = <gmap.Marker>{}.obs;
RxSet<gmap.Polyline> googlePolylines = <gmap.Polyline>{}.obs;
// OSM Data
RxList<osm.LatLng> osmPolyline = <osm.LatLng>[].obs;
final String googleApiKey = Constant.mapAPIKey;
final Rx<UserModel> driverUser = UserModel().obs;
Rx<RatingModel> ratingModel = RatingModel().obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null) {
cabOrder.value = args['cabOrderModel'] as CabOrderModel;
calculateTotalAmount();
_setMarkers();
_getGoogleRoute();
_getOsmRoute();
}
fetchDriverDetails();
}
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
Future<void> fetchDriverDetails() async {
if (cabOrder.value.driverId != null) {
await FireStoreUtils.getUserProfile(cabOrder.value.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
}
});
print(driverUser.value.toJson());
await FireStoreUtils.getReviewsbyID(cabOrder.value.id.toString()).then((value) {
if (value != null) {
ratingModel.value = value;
}
});
}
}
void calculateTotalAmount() {
taxAmount = 0.0.obs;
discount = 0.0.obs;
subTotal.value = double.parse(cabOrder.value.subTotal.toString());
discount.value = double.parse(cabOrder.value.discount ?? '0.0');
if (cabOrder.value.taxSetting != null) {
for (var element in cabOrder.value.taxSetting!) {
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
}
}
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
update();
}
void _setMarkers() {
final sourceLat = cabOrder.value.sourceLocation!.latitude;
final sourceLng = cabOrder.value.sourceLocation!.longitude;
final destLat = cabOrder.value.destinationLocation!.latitude;
final destLng = cabOrder.value.destinationLocation!.longitude;
googleMarkers.value = {
gmap.Marker(markerId: const gmap.MarkerId('source'), position: gmap.LatLng(sourceLat!, sourceLng!), icon: gmap.BitmapDescriptor.defaultMarkerWithHue(gmap.BitmapDescriptor.hueGreen)),
gmap.Marker(markerId: const gmap.MarkerId('destination'), position: gmap.LatLng(destLat!, destLng!), icon: gmap.BitmapDescriptor.defaultMarkerWithHue(gmap.BitmapDescriptor.hueRed)),
};
}
///Google Directions API
Future<void> _getGoogleRoute() async {
final src = cabOrder.value.sourceLocation;
final dest = cabOrder.value.destinationLocation;
final url = "https://maps.googleapis.com/maps/api/directions/json?origin=${src!.latitude},${src.longitude}&destination=${dest!.latitude},${dest.longitude}&key=$googleApiKey";
final response = await http.get(Uri.parse(url));
final data = jsonDecode(response.body);
if (data["routes"].isNotEmpty) {
final points = data["routes"][0]["overview_polyline"]["points"];
final polylinePoints = PolylinePoints.decodePolyline(points);
final polylineCoords = polylinePoints.map((p) => gmap.LatLng(p.latitude, p.longitude)).toList();
googlePolylines.value = {gmap.Polyline(polylineId: const gmap.PolylineId("google_route"), color: AppThemeData.onDemandDark100, width: 5, points: polylineCoords)};
}
}
/// OSM Route (OSRM API)
Future<void> _getOsmRoute() async {
final src = cabOrder.value.sourceLocation;
final dest = cabOrder.value.destinationLocation;
final url = "http://router.project-osrm.org/route/v1/driving/${src!.longitude},${src.latitude};${dest!.longitude},${dest.latitude}?overview=full&geometries=geojson";
final response = await http.get(Uri.parse(url));
final data = jsonDecode(response.body);
if (data["routes"].isNotEmpty) {
final coords = data["routes"][0]["geometry"]["coordinates"] as List<dynamic>;
osmPolyline.value = coords.map((c) => osm.LatLng(c[1].toDouble(), c[0].toDouble())).toList();
}
}
}

View File

@@ -0,0 +1,34 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/screen_ui/rental_service/rental_home_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
import '../screen_ui/rental_service/my_rental_booking_screen.dart';
class CabRentalDashboardControllers extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
// TODO: implement onInit
getTaxList();
if (Constant.walletSetting == false) {
pageList.value = [RentalHomeScreen(), MyRentalBookingScreen(), const ProfileScreen()];
} else {
pageList.value = [RentalHomeScreen(), MyRentalBookingScreen(), const WalletScreen(), const ProfileScreen()];
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
}

View File

@@ -0,0 +1,133 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/cab_order_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/collection_name.dart';
import '../models/rating_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
import '../constant/constant.dart';
import '../themes/show_toast_dialog.dart';
class CabReviewController extends GetxController {
RxBool isLoading = true.obs;
final Rx<CabOrderModel?> order = Rx<CabOrderModel?>(null);
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
final RxDouble ratings = 0.0.obs;
final Rx<TextEditingController> comment = TextEditingController().obs;
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
final RxInt futureCount = 0.obs;
final RxInt futureSum = 0.obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args['order'] != null) {
order.value = args['order'] as CabOrderModel;
getReview();
}
}
/// Fetch old review + driver stats
Future<void> getReview() async {
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0;
comment.value.text = value.comment ?? "";
}
});
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
if (ratingModel.value != null) {
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
futureCount.value = userReviewsCount - 1;
futureSum.value = userReviewsSum - oldRating;
} else {
futureCount.value = userReviewsCount;
futureSum.value = userReviewsSum;
}
}
});
isLoading.value = false;
}
/// Save / update review
Future<void> submitReview() async {
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
ShowToastDialog.showToast("Please provide rating and comment".tr);
return;
}
ShowToastDialog.showLoader("Submit in...".tr);
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
if (user != null) {
user.reviewsCount = (futureCount.value + 1).toString();
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
}
if (ratingModel.value != null) {
/// Update existing review
final updatedRating = RatingModel(
id: ratingModel.value!.id,
comment: comment.value.text,
photos: ratingModel.value?.photos ?? [],
rating: ratings.value,
orderId: ratingModel.value!.orderId,
driverId: ratingModel.value!.driverId,
customerId: ratingModel.value!.customerId,
vendorId: ratingModel.value?.vendorId,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(updatedRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
} else {
/// New review
final docRef = FireStoreUtils.fireStore.collection(CollectionName.itemsReview).doc();
final newRating = RatingModel(
id: docRef.id,
comment: comment.value.text,
photos: [],
rating: ratings.value,
orderId: order.value?.id,
driverId: order.value?.driverId.toString(),
customerId: Constant.userModel?.id,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(newRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
}
ShowToastDialog.closeLoader();
Get.back(result: true);
}
@override
void onClose() {
comment.value.dispose();
super.onClose();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
import '../models/cashback_model.dart';
import 'package:get/get.dart';
import '../service/fire_store_utils.dart';
class CashbackController extends GetxController {
RxList<CashbackModel> cashbackList = <CashbackModel>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getCashback();
super.onInit();
}
Future<void> getCashback() async {
await FireStoreUtils.getCashbackList().then((value) {
if (value.isNotEmpty) {
cashbackList.value = value;
}
});
isLoading.value = false;
}
}

View File

@@ -0,0 +1,62 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../models/vendor_category_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class CategoryRestaurantController extends GetxController {
RxBool isLoading = true.obs;
RxBool dineIn = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Rx<VendorCategoryModel> vendorCategoryModel = VendorCategoryModel().obs;
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorCategoryModel.value = argumentData['vendorCategoryModel'];
dineIn.value = argumentData['dineIn'];
await getZone();
await getRestaurant();
}
Future.delayed(Duration(seconds: 1), () {
isLoading.value = false;
});
}
Future getRestaurant() async {
FireStoreUtils.getAllNearestRestaurantByCategoryId(categoryId: vendorCategoryModel.value.id.toString(), isDining: dineIn.value).listen((
event,
) async {
allNearestRestaurant.clear();
allNearestRestaurant.addAll(event);
});
}
Future<void> getZone() async {
await FireStoreUtils.getZone().then((value) {
if (value != null) {
for (int i = 0; i < value.length; i++) {
if (Constant.isPointInPolygon(
LatLng(Constant.selectedLocation.location!.latitude ?? 0.0, Constant.selectedLocation.location!.longitude ?? 0.0),
value[i].area!,
)) {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = true;
break;
} else {
Constant.isZoneAvailable = false;
}
}
}
});
}
}

View File

@@ -0,0 +1,44 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/language_model.dart';
import '../service/fire_store_utils.dart';
import 'package:customer/utils/preferences.dart';
import 'package:get/get.dart';
import '../constant/collection_name.dart';
class ChangeLanguageController extends GetxController {
Rx<LanguageModel> selectedLanguage = LanguageModel().obs;
RxList<LanguageModel> languageList = <LanguageModel>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getLanguage();
super.onInit();
}
Future<void> getLanguage() async {
await FireStoreUtils.fireStore.collection(CollectionName.settings).doc("languages").get().then((event) {
if (event.exists) {
List languageListTemp = event.data()!["list"];
for (var element in languageListTemp) {
LanguageModel languageModel = LanguageModel.fromJson(element);
languageList.add(languageModel);
}
if (Preferences.getString(Preferences.languageCodeKey).toString().isNotEmpty) {
LanguageModel pref = Constant.getLanguage();
for (var element in languageList) {
if (element.slug == pref.slug) {
selectedLanguage.value = element;
}
}
}
}
});
isLoading.value = false;
}
}

View File

@@ -0,0 +1,142 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:image_picker/image_picker.dart';
import '../models/conversation_model.dart';
import '../models/inbox_model.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import '../service/send_notification.dart';
class ChatController extends GetxController {
Rx<TextEditingController> messageController = TextEditingController().obs;
final ScrollController scrollController = ScrollController();
@override
void onInit() {
// TODO: implement onInit
if (scrollController.hasClients) {
Timer(const Duration(milliseconds: 500), () => scrollController.jumpTo(scrollController.position.maxScrollExtent));
}
getArgument();
super.onInit();
}
RxBool isLoading = true.obs;
RxString orderId = "".obs;
RxString customerId = "".obs;
RxString customerName = "".obs;
RxString customerProfileImage = "".obs;
RxString restaurantId = "".obs;
RxString restaurantName = "".obs;
RxString restaurantProfileImage = "".obs;
RxString token = "".obs;
RxString chatType = "".obs;
void getArgument() {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
orderId.value = argumentData['orderId'];
customerId.value = argumentData['customerId'];
customerName.value = argumentData['customerName'];
customerProfileImage.value = argumentData['customerProfileImage'] ?? "";
restaurantId.value = argumentData['restaurantId'];
restaurantName.value = argumentData['restaurantName'];
restaurantProfileImage.value = argumentData['restaurantProfileImage'] ?? "";
token.value = argumentData['token'] ?? "";
chatType.value = argumentData['chatType'];
}
isLoading.value = false;
}
Future<void> sendMessage(String message, Url? url, String videoThumbnail, String messageType) async {
InboxModel inboxModel = InboxModel(
lastSenderId: customerId.value,
customerId: customerId.value,
customerName: customerName.value,
restaurantId: restaurantId.value,
restaurantName: restaurantName.value,
createdAt: Timestamp.now(),
orderId: orderId.value,
customerProfileImage: customerProfileImage.value,
restaurantProfileImage: restaurantProfileImage.value,
lastMessage: messageController.value.text,
chatType: chatType.value,
);
print("chatType: ${chatType.value}");
if (chatType.value == "Driver") {
await FireStoreUtils.addDriverInbox(inboxModel);
} else if (chatType.value == "worker" || chatType.value == "Worker") {
await FireStoreUtils.addWorkerInbox(inboxModel);
} else if (chatType.value == "provider" || chatType.value == "Provider") {
await FireStoreUtils.addProviderInbox(inboxModel);
} else {
await FireStoreUtils.addRestaurantInbox(inboxModel);
}
ConversationModel conversationModel = ConversationModel(
id: const Uuid().v4(),
message: message,
senderId: customerId.value,
receiverId: restaurantId.value,
createdAt: Timestamp.now(),
url: url,
orderId: orderId.value,
messageType: messageType,
videoThumbnail: videoThumbnail,
);
if (url != null) {
if (url.mime.contains('image')) {
conversationModel.message = "sent a message".tr;
} else if (url.mime.contains('video')) {
conversationModel.message = "Sent a video".tr;
} else if (url.mime.contains('audio')) {
conversationModel.message = "Sent a audio".tr;
}
}
if (chatType.value == "Driver") {
await FireStoreUtils.addDriverChat(conversationModel);
} else if (chatType.value == "worker" || chatType.value == "Worker") {
await FireStoreUtils.addWorkerChat(conversationModel);
} else if (chatType.value == "provider" || chatType.value == "Provider") {
await FireStoreUtils.addProviderChat(conversationModel);
} else {
await FireStoreUtils.addRestaurantChat(conversationModel);
}
//await SendNotification.sendChatFcmMessage(customerName.value, conversationModel.message.toString(), token.value, {});
await SendNotification.sendChatFcmMessage(customerName.value, conversationModel.message.toString(), token.value, {
"type": "chat",
"chatType": chatType.value,
"orderId": orderId.value,
"customerId": customerId.value,
"customerName": customerName.value,
"customerProfileImage": customerProfileImage.value,
"restaurantId": restaurantId.value,
"restaurantName": restaurantName.value,
"restaurantProfileImage": restaurantProfileImage.value,
"token": token.value,
});
}
final ImagePicker imagePicker = ImagePicker();
// Future pickFile({required ImageSource source}) async {
// try {
// XFile? image = await imagePicker.pickImage(source: source);
// if (image == null) return;
// Url url = await FireStoreUtils.uploadChatImageToFireStorage(File(image.path), Get.context!);
// sendMessage('', url, '', 'image');
// Get.back();
// } on PlatformException catch (e) {
// ShowToastDialog.showToast("${"failed_to_pick".tr} : \n $e");
// }
// }
}

View File

@@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/cab_order_model.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
class ComplainController extends GetxController {
Rx<CabOrderModel> order = CabOrderModel().obs;
final Rx<TextEditingController> title = TextEditingController().obs;
final Rx<TextEditingController> comment = TextEditingController().obs;
final RxBool isLoading = false.obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args is Map && args['order'] is CabOrderModel) {
order.value = args['order'] as CabOrderModel;
getComplain();
} else {
ShowToastDialog.showToast("Order data not found".tr);
Get.back();
}
}
Future<void> getComplain() async {
isLoading.value = true;
try {
final data = await FireStoreUtils.getRideComplainData(order.value.id ?? '');
if (data != null) {
title.value.text = data['title'] ?? '';
comment.value.text = data['description'] ?? '';
}
} catch (e) {
ShowToastDialog.showToast("Failed to load complaint".tr);
} finally {
isLoading.value = false;
}
}
Future<void> submitComplain() async {
// Validation
if (title.value.text.trim().isEmpty) {
ShowToastDialog.showToast("Please enter complaint title".tr);
return;
}
if (comment.value.text.trim().isEmpty) {
ShowToastDialog.showToast("Please enter complaint description".tr);
return;
}
isLoading.value = true;
ShowToastDialog.showLoader("Please wait...");
try {
// Check if complaint already exists
bool exists = await FireStoreUtils.isRideComplainAdded(order.value.id ?? '');
if (!exists) {
await FireStoreUtils.setRideComplain(
orderId: order.value.id ?? '',
title: title.value.text.trim(),
description: comment.value.text.trim(),
customerID: order.value.authorID ?? '',
customerName: "${order.value.author?.firstName ?? ''} ${order.value.author?.lastName ?? ''}".trim(),
driverID: order.value.driverId ?? '',
driverName: "${order.value.driver?.firstName ?? ''} ${order.value.driver?.lastName ?? ''}".trim(),
);
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Your complaint has been submitted to admin".tr);
Get.back();
} else {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Your complaint is already submitted".tr);
}
} catch (e) {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Something went wrong, please try again".tr);
} finally {
isLoading.value = false;
}
}
@override
void onClose() {
title.value.dispose();
comment.value.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,46 @@
import 'package:customer/constant/constant.dart';
import '../screen_ui/multi_vendor_service/favourite_screens/favourite_screen.dart';
import '../screen_ui/multi_vendor_service/home_screen/home_screen.dart';
import '../screen_ui/multi_vendor_service/home_screen/home_screen_two.dart';
import '../screen_ui/multi_vendor_service/order_list_screen/order_screen.dart';
import '../screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class DashBoardController extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
// TODO: implement onInit
getTaxList();
if (Constant.sectionConstantModel!.theme == "theme_2") {
if (Constant.walletSetting == false) {
pageList.value = [const HomeScreen(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
} else {
pageList.value = [const HomeScreen(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
}
} else {
if (Constant.walletSetting == false) {
pageList.value = [const HomeScreenTwo(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
} else {
pageList.value = [const HomeScreenTwo(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
}
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
DateTime? currentBackPressTime;
RxBool canPopNow = false.obs;
}

View File

@@ -0,0 +1,37 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/screen_ui/ecommarce/home_e_commerce_screen.dart';
import '../screen_ui/multi_vendor_service/favourite_screens/favourite_screen.dart';
import '../screen_ui/multi_vendor_service/order_list_screen/order_screen.dart';
import '../screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class DashBoardEcommerceController extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
// TODO: implement onInit
getTaxList();
if (Constant.walletSetting == false) {
pageList.value = [const HomeECommerceScreen(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
} else {
pageList.value = [const HomeECommerceScreen(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
DateTime? currentBackPressTime;
RxBool canPopNow = false.obs;
}

View File

@@ -0,0 +1,34 @@
import '../models/dine_in_booking_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class DineInBookingController extends GetxController {
RxBool isLoading = true.obs;
RxBool isFeature = true.obs;
RxList<DineInBookingModel> featureList = <DineInBookingModel>[].obs;
RxList<DineInBookingModel> historyList = <DineInBookingModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getDineInBooking();
super.onInit();
}
Future<void> getDineInBooking() async {
await FireStoreUtils.getDineInBooking(true).then(
(value) {
featureList.value = value;
},
);
await FireStoreUtils.getDineInBooking(false).then(
(value) {
historyList.value = value;
},
);
isLoading.value = false;
}
}

View File

@@ -0,0 +1,24 @@
import 'package:customer/models/dine_in_booking_model.dart';
import 'package:get/get.dart';
class DineInBookingDetailsController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Rx<DineInBookingModel> bookingModel = DineInBookingModel().obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
bookingModel.value = argumentData['bookingModel'];
}
isLoading.value = false;
update();
}
}

View File

@@ -0,0 +1,100 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../models/banner_model.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class DineInController extends GetxController {
RxBool isLoading = true.obs;
RxBool isPopular = true.obs;
@override
void onInit() {
getCategory();
getData();
// TODO: implement onInit
super.onInit();
}
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
RxList<VendorModel> popularRestaurantList = <VendorModel>[].obs;
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
RxInt currentBottomPage = 0.obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
Future<void> getData() async {
isLoading.value = true;
await getZone();
FireStoreUtils.getAllNearestRestaurant(isDining: true).listen((event) async {
newArrivalRestaurantList.clear();
allNearestRestaurant.clear();
popularRestaurantList.clear();
allNearestRestaurant.addAll(event);
newArrivalRestaurantList.addAll(event);
popularRestaurantList.addAll(event);
popularRestaurantList.sort(
(a, b) => Constant.calculateReview(reviewCount: b.reviewsCount.toString(), reviewSum: b.reviewsSum.toString())
.compareTo(Constant.calculateReview(reviewCount: a.reviewsCount.toString(), reviewSum: a.reviewsSum.toString())),
);
newArrivalRestaurantList.sort(
(a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()),
);
});
update();
isLoading.value = false;
}
Future<void> getCategory() async {
await FireStoreUtils.getHomeVendorCategory().then(
(value) {
vendorCategoryModel.value = value;
},
);
await FireStoreUtils.getHomeBottomBanner().then(
(value) {
bannerBottomModel.value = value;
},
);
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then(
(value) {
favouriteList.value = value;
},
);
}
}
Future<void> getZone() async {
await FireStoreUtils.getZone().then((value) {
if (value != null) {
for (int i = 0; i < value.length; i++) {
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location!.latitude ?? 0.0, Constant.selectedLocation.location!.longitude ?? 0.0), value[i].area!)) {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = true;
break;
} else {
Constant.isZoneAvailable = false;
}
}
}
});
}
}

View File

@@ -0,0 +1,287 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/dine_in_booking_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../screen_ui/multi_vendor_service/dine_in_booking/dine_in_booking_screen.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../service/send_notification.dart';
import '../themes/show_toast_dialog.dart';
class DineInRestaurantDetailsController extends GetxController {
Rx<TextEditingController> searchEditingController = TextEditingController().obs;
Rx<TextEditingController> additionRequestController = TextEditingController().obs;
RxBool isLoading = true.obs;
RxBool firstVisit = false.obs;
Rx<PageController> pageController = PageController().obs;
RxInt currentPage = 0.obs;
RxInt noOfQuantity = 1.obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
RxList tags = [].obs;
// List occasionList = ["Birthday", "Anniversary"];
RxList<String> occasionList = ["Birthday", "Anniversary"].obs;
/// Localized title for each occasion
String getLocalizedOccasion(String key) {
switch (key) {
case "Birthday":
return "Birthday".tr;
case "Anniversary":
return "Anniversary".tr;
default:
return key;
}
}
RxString selectedOccasion = "".obs;
RxList<DateModel> dateList = <DateModel>[].obs;
RxList<TimeModel> timeSlotList = <TimeModel>[].obs;
Rx<Timestamp> selectedDate = Timestamp.now().obs;
RxString selectedTimeSlot = '6:00 PM'.obs;
RxString selectedTimeDiscount = '0'.obs;
RxString selectedTimeDiscountType = ''.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
getRecord();
super.onInit();
}
Future<void> orderBook() async {
ShowToastDialog.showLoader("Please wait...".tr);
DateTime dt = selectedDate.value.toDate();
String hour = DateFormat("kk:mm").format(DateFormat('hh:mm a').parse((Intl.getCurrentLocale() == "en_US") ? selectedTimeSlot.value : selectedTimeSlot.value.toLowerCase()));
dt = DateTime(dt.year, dt.month, dt.day, int.parse(hour.split(":")[0]), int.parse(hour.split(":")[1]), dt.second, dt.millisecond, dt.microsecond);
selectedDate.value = Timestamp.fromDate(dt);
DineInBookingModel dineInBookingModel = DineInBookingModel(
id: Constant.getUuid(),
author: Constant.userModel,
authorID: FireStoreUtils.getCurrentUid(),
createdAt: Timestamp.now(),
date: selectedDate.value,
status: Constant.orderPlaced,
vendor: vendorModel.value,
specialRequest: additionRequestController.value.text.isEmpty ? "" : additionRequestController.value.text,
vendorID: vendorModel.value.id,
guestEmail: Constant.userModel!.email,
guestFirstName: Constant.userModel!.firstName,
guestLastName: Constant.userModel!.lastName,
guestPhone: Constant.userModel!.phoneNumber,
occasion: selectedOccasion.value,
discount: selectedTimeDiscount.value,
discountType: selectedTimeDiscountType.value,
totalGuest: noOfQuantity.value.toString(),
firstVisit: firstVisit.value);
await FireStoreUtils.setBookedOrder(dineInBookingModel);
await SendNotification.sendFcmMessage(Constant.dineInPlaced, vendorModel.value.fcmToken.toString(), {});
ShowToastDialog.closeLoader();
Get.back();
Get.to(const DineInBookingScreen());
ShowToastDialog.showToast('Dine-In Request submitted successfully.'.tr);
}
void getRecord() {
for (int i = 0; i < 7; i++) {
final now = DateTime.now().add(Duration(days: i));
var day = DateFormat('EEEE').format(now);
if (vendorModel.value.specialDiscount?.isNotEmpty == true && vendorModel.value.specialDiscountEnable == true) {
for (var element in vendorModel.value.specialDiscount!) {
if (day == element.day.toString()) {
if (element.timeslot!.isNotEmpty) {
SpecialDiscountTimeslot employeeWithMaxSalary =
element.timeslot!.reduce((item1, item2) => double.parse(item1.discount.toString()) > double.parse(item2.discount.toString()) ? item1 : item2);
if (employeeWithMaxSalary.discountType == "dinein") {
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: employeeWithMaxSalary.discount.toString());
dateList.add(model);
} else {
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
dateList.add(model);
}
} else {
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
dateList.add(model);
}
}
}
} else {
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
dateList.add(model);
}
}
selectedDate.value = dateList.first.date;
timeSet(selectedDate.value);
if (timeSlotList.isNotEmpty) {
selectedTimeSlot.value = DateFormat('hh:mm a').format(timeSlotList[0].time!);
}
}
void timeSet(Timestamp selectedDate) {
timeSlotList.clear();
for (DateTime time = Constant.stringToDate(vendorModel.value.openDineTime.toString());
time.isBefore(Constant.stringToDate(vendorModel.value.closeDineTime.toString()));
time = time.add(const Duration(minutes: 30))) {
final now = DateTime.parse(selectedDate.toDate().toString());
var day = DateFormat('EEEE').format(now);
var date = DateFormat('dd-MM-yyyy').format(now);
if (vendorModel.value.specialDiscount?.isNotEmpty == true && vendorModel.value.specialDiscountEnable == true) {
for (var element in vendorModel.value.specialDiscount!) {
if (day == element.day.toString()) {
if (element.timeslot!.isNotEmpty) {
for (var element in element.timeslot!) {
if (element.discountType == "dinein") {
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
var selected = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${DateFormat.Hm().format(time)}");
if (isCurrentDateInRangeDineIn(start, end, selected)) {
var contains = timeSlotList.where((element) => element.time == time);
if (contains.isNotEmpty) {
var index = timeSlotList.indexWhere((element) => element.time == time);
if (timeSlotList[index].discountPer == "0") {
timeSlotList.removeAt(index);
TimeModel model = TimeModel(time: time, discountPer: element.discount, discountType: element.type);
timeSlotList.insert(index == 0 ? 0 : index, model);
}
} else {
TimeModel model = TimeModel(time: time, discountPer: element.discount, discountType: element.type);
timeSlotList.add(model);
}
} else {
var contains = timeSlotList.where((element) => element.time == time);
if (contains.isEmpty) {
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
timeSlotList.add(model);
}
}
} else {
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
timeSlotList.add(model);
}
}
} else {
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
timeSlotList.add(model);
}
}
}
} else {
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
timeSlotList.add(model);
}
}
}
void animateSlider() {
if (vendorModel.value.photos != null && vendorModel.value.photos!.isNotEmpty) {
Timer.periodic(const Duration(seconds: 2), (Timer timer) {
if (currentPage < vendorModel.value.photos!.length) {
currentPage++;
} else {
currentPage.value = 0;
}
if (pageController.value.hasClients) {
pageController.value.animateToPage(
currentPage.value,
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
}
});
}
}
Rx<VendorModel> vendorModel = VendorModel().obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorModel.value = argumentData['vendorModel'];
}
animateSlider();
statusCheck();
isLoading.value = false;
await getFavouriteList();
update();
}
Future<void> getFavouriteList() async {
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then(
(value) {
favouriteList.value = value;
},
);
}
await FireStoreUtils.getVendorCuisines(vendorModel.value.id.toString()).then(
(value) {
tags.value = value;
},
);
update();
}
RxBool isOpen = false.obs;
void statusCheck() {
final now = DateTime.now();
var day = DateFormat('EEEE', 'en_US').format(now);
var date = DateFormat('dd-MM-yyyy').format(now);
for (var element in vendorModel.value.workingHours!) {
if (day == element.day.toString()) {
if (element.timeslot!.isNotEmpty) {
for (var element in element.timeslot!) {
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
if (isCurrentDateInRange(start, end)) {
isOpen.value = true;
}
}
}
}
}
}
bool isCurrentDateInRangeDineIn(DateTime startDate, DateTime endDate, DateTime selected) {
return selected.isAtSameMomentAs(startDate) || selected.isAtSameMomentAs(endDate) || selected.isAfter(startDate) && selected.isBefore(endDate);
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
}
class DateModel {
late Timestamp date;
late String discountPer;
DateModel({required this.date, required this.discountPer});
}
class TimeModel {
DateTime? time;
String? discountPer;
String? discountType;
TimeModel({required this.time, required this.discountPer, required this.discountType});
}

View File

@@ -0,0 +1,28 @@
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:get/get.dart';
class DiscountRestaurantListController extends GetxController {
RxBool isLoading = true.obs;
RxList<VendorModel> vendorList = <VendorModel>[].obs;
RxList<CouponModel> couponList = <CouponModel>[].obs;
RxString title = "Restaurants".obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorList.value = argumentData['vendorList'];
couponList.value = argumentData['couponList'];
title.value = argumentData['title'] ?? "Restaurants";
}
isLoading.value = false;
}
}

View File

@@ -0,0 +1,77 @@
import 'dart:io';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/user_model.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import '../themes/show_toast_dialog.dart';
class EditProfileController extends GetxController {
RxBool isLoading = true.obs;
Rx<UserModel> userModel = UserModel().obs;
Rx<TextEditingController> firstNameController = TextEditingController().obs;
Rx<TextEditingController> lastNameController = TextEditingController().obs;
Rx<TextEditingController> emailController = TextEditingController().obs;
Rx<TextEditingController> phoneNumberController = TextEditingController().obs;
Rx<TextEditingController> countryCodeController = TextEditingController(text: "+91").obs;
@override
void onInit() {
getData();
super.onInit();
}
Future<void> getData() async {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
if (value != null) {
userModel.value = value;
firstNameController.value.text = userModel.value.firstName.toString();
lastNameController.value.text = userModel.value.lastName.toString();
emailController.value.text = userModel.value.email.toString();
phoneNumberController.value.text = userModel.value.phoneNumber.toString();
countryCodeController.value.text = userModel.value.countryCode.toString();
profileImage.value = userModel.value.profilePictureURL ?? "";
}
});
isLoading.value = false;
}
Future<void> saveData() async {
ShowToastDialog.showLoader("Please wait...".tr);
if (Constant().hasValidUrl(profileImage.value) == false && profileImage.value.isNotEmpty) {
profileImage.value = await Constant.uploadUserImageToFireStorage(
File(profileImage.value),
"profileImage/${FireStoreUtils.getCurrentUid()}",
File(profileImage.value).path.split('/').last,
);
}
userModel.value.firstName = firstNameController.value.text;
userModel.value.lastName = lastNameController.value.text;
userModel.value.profilePictureURL = profileImage.value;
await FireStoreUtils.updateUser(userModel.value).then((value) {
ShowToastDialog.closeLoader();
//Get.back(result: true);
});
}
final ImagePicker _imagePicker = ImagePicker();
RxString profileImage = "".obs;
Future pickFile({required ImageSource source}) async {
try {
XFile? image = await _imagePicker.pickImage(source: source);
if (image == null) return;
Get.back();
profileImage.value = image.path;
} on PlatformException catch (e) {
ShowToastDialog.showToast("${"failed_to_pick".tr} : \n $e");
}
}
}

View File

@@ -0,0 +1,83 @@
import 'package:customer/service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/user_model.dart';
class EnterManuallyLocationController extends GetxController {
Rx<UserModel> userModel = UserModel().obs;
RxList<ShippingAddress> shippingAddressList = <ShippingAddress>[].obs;
List saveAsList = ['Home', 'Work', 'Hotel', 'other'].obs;
RxString selectedSaveAs = "Home".obs;
Rx<TextEditingController> houseBuildingTextEditingController = TextEditingController().obs;
Rx<TextEditingController> localityEditingController = TextEditingController().obs;
Rx<TextEditingController> landmarkEditingController = TextEditingController().obs;
Rx<UserLocation> location = UserLocation().obs;
Rx<ShippingAddress> shippingModel = ShippingAddress().obs;
RxBool isLoading = false.obs;
RxBool isDefault = false.obs;
RxString mode = "Add".obs;
@override
void onInit() {
getArgument();
super.onInit();
}
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
//check mode
mode.value = argumentData['mode'] ?? "Add";
//check address
if (argumentData['address'] != null && argumentData['address'] is ShippingAddress) {
shippingModel.value = argumentData['address'];
setData(shippingModel.value);
}
}
await getUser();
isLoading.value = false;
update();
}
void setData(ShippingAddress shippingAddress) {
shippingModel.value = shippingAddress;
houseBuildingTextEditingController.value.text = shippingAddress.address.toString();
localityEditingController.value.text = shippingAddress.locality.toString();
landmarkEditingController.value.text = shippingAddress.landmark.toString();
selectedSaveAs.value = shippingAddress.addressAs.toString();
location.value = shippingAddress.location!;
}
Future<void> getUser() async {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
if (value != null) {
userModel.value = value;
if (userModel.value.shippingAddress != null) {
shippingAddressList.value = userModel.value.shippingAddress!;
}
}
});
}
String getLocalizedSaveAs(String key) {
switch (key) {
case 'Home':
return 'Home'.tr;
case 'Work':
return 'Work'.tr;
case 'Hotel':
return 'Hotel'.tr;
case 'Other':
return 'Other'.tr;
default:
return key;
}
}
}

View File

@@ -0,0 +1,93 @@
import 'package:customer/constant/collection_name.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/favourite_item_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class FavouriteController extends GetxController {
RxBool favouriteRestaurant = true.obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
RxList<VendorModel> favouriteVendorList = <VendorModel>[].obs;
RxList<FavouriteItemModel> favouriteItemList = <FavouriteItemModel>[].obs;
RxList<ProductModel> favouriteFoodList = <ProductModel>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
Future<void> getData() async {
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
await FireStoreUtils.getFavouriteItem().then((value) {
favouriteItemList.value = value;
});
for (var element in favouriteList) {
await FireStoreUtils.getVendorById(element.restaurantId.toString()).then((value) async {
if (value != null) {
if ((Constant.isSubscriptionModelApplied == true || value.adminCommission?.isEnabled == true) && value.subscriptionPlan != null) {
if (value.subscriptionTotalOrders == "-1") {
favouriteVendorList.add(value);
} else {
print("Restaurant :: ${value.title.toString()}");
if ((value.subscriptionExpiryDate != null && value.subscriptionExpiryDate!.toDate().isBefore(DateTime.now()) == false) ||
value.subscriptionPlan?.expiryDay == '-1') {
if (value.subscriptionTotalOrders != '0') {
favouriteVendorList.add(value);
}
}
}
} else {
favouriteVendorList.add(value);
}
}
});
}
for (var element in favouriteItemList) {
await FireStoreUtils.getProductById(element.productId.toString()).then((value) async {
if (value != null) {
await FireStoreUtils.fireStore.collection(CollectionName.vendors).doc(value.vendorID.toString()).get().then((value1) async {
if (value1.exists) {
VendorModel vendorModel = VendorModel.fromJson(value1.data()!);
if(value.publish == true){
if (Constant.isSubscriptionModelApplied == true || vendorModel.adminCommission?.isEnabled == true) {
if (vendorModel.subscriptionPlan != null) {
if (vendorModel.subscriptionTotalOrders == "-1") {
favouriteFoodList.add(value);
} else {
if ((vendorModel.subscriptionExpiryDate != null && vendorModel.subscriptionExpiryDate!.toDate().isBefore(DateTime.now()) == false) ||
vendorModel.subscriptionPlan?.expiryDay == "-1") {
if (vendorModel.subscriptionTotalOrders != '0') {
favouriteFoodList.add(value);
}
}
}
}
} else {
favouriteFoodList.add(value);
}
}
}
});
}
});
}
}
isLoading.value = false;
}
}

View File

@@ -0,0 +1,73 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/category_model.dart';
import 'package:customer/models/favorite_ondemand_service_model.dart';
import 'package:customer/models/provider_serivce_model.dart';
import 'package:customer/screen_ui/auth_screens/login_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class FavouriteOndemmandController extends GetxController {
// Add your controller logic here
Rx<bool> isLoading = false.obs;
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
RxList<CategoryModel> categories = <CategoryModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
Future<void> getData() async {
isLoading.value = true;
await FireStoreUtils.getOnDemandCategory().then((catValue) {
categories.value = catValue;
});
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((favList) {
lstFav.value = favList;
});
isLoading.value = false;
}
void toggleFavourite(ProviderServiceModel provider) {
if (Constant.userModel == null) {
Get.to(LoginScreen());
} else {
var contain = lstFav.where((element) => element.service_id == provider.id);
if (contain.isNotEmpty) {
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
section_id: provider.sectionId,
service_id: provider.id,
user_id: FireStoreUtils.getCurrentUid(),
serviceAuthorId: provider.author,
);
FireStoreUtils.removeFavouriteOndemandService(favouriteModel);
lstFav.removeWhere((item) => item.service_id == provider.id);
} else {
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
section_id: provider.sectionId,
service_id: provider.id,
user_id: FireStoreUtils.getCurrentUid(),
serviceAuthorId: provider.author,
);
FireStoreUtils.setFavouriteOndemandSection(favouriteModel);
lstFav.add(favouriteModel);
}
}
}
/// Get category by id safely from cached categories
Future<CategoryModel?> getCategory(String? categoryId) async {
if (categoryId == null || categoryId.isEmpty) return null;
// Try to find category from cached list
CategoryModel? cat = categories.firstWhereOrNull((element) => element.id == categoryId);
// If not found, fetch from Firestore
cat ??= await FireStoreUtils.getCategoryById(categoryId);
return cat;
}
}

View File

@@ -0,0 +1,191 @@
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/controllers/dash_board_controller.dart';
import 'package:customer/models/advertisement_model.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/utils/preferences.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../models/banner_model.dart';
import '../models/story_model.dart';
import '../service/cart_provider.dart';
import '../service/fire_store_utils.dart';
class FoodHomeController extends GetxController {
DashBoardController dashBoardController = Get.find<DashBoardController>();
final CartProvider cartProvider = CartProvider();
Future<void> getCartData() async {
cartProvider.cartStream.listen((event) async {
cartItem.clear();
cartItem.addAll(event);
});
update();
}
RxBool isLoading = true.obs;
RxBool isListView = true.obs;
RxBool isPopular = true.obs;
RxString selectedOrderTypeValue = "Delivery".tr.obs;
Rx<PageController> pageController = PageController(viewportFraction: 0.877).obs;
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
RxInt currentPage = 0.obs;
RxInt currentBottomPage = 0.obs;
late TabController tabController;
@override
void onInit() async {
await getData();
super.onInit();
}
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
RxList<VendorModel> popularRestaurantList = <VendorModel>[].obs;
RxList<VendorModel> couponRestaurantList = <VendorModel>[].obs;
RxList<CouponModel> couponList = <CouponModel>[].obs;
RxList<StoryModel> storyList = <StoryModel>[].obs;
RxList<BannerModel> bannerModel = <BannerModel>[].obs;
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
Future<void> getData() async {
isLoading.value = true;
getCartData();
selectedOrderTypeValue.value = Preferences.getString(Preferences.foodDeliveryType, defaultValue: "Delivery");
await getZone();
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
popularRestaurantList.clear();
newArrivalRestaurantList.clear();
allNearestRestaurant.clear();
advertisementList.clear();
allNearestRestaurant.addAll(event);
newArrivalRestaurantList.addAll(event);
popularRestaurantList.addAll(event);
Constant.restaurantList = allNearestRestaurant;
popularRestaurantList.sort(
(a, b) => Constant.calculateReview(
reviewCount: b.reviewsCount.toString(),
reviewSum: b.reviewsSum.toString(),
).compareTo(Constant.calculateReview(reviewCount: a.reviewsCount.toString(), reviewSum: a.reviewsSum.toString())),
);
newArrivalRestaurantList.sort((a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()));
await getVendorCategory();
await FireStoreUtils.getHomeCoupon().then((value) {
couponRestaurantList.clear();
couponList.clear();
for (var element1 in value) {
for (var element in allNearestRestaurant) {
if (element1.vendorID == element.id && element1.expiresAt!.toDate().isAfter(DateTime.now())) {
couponList.add(element1);
couponRestaurantList.add(element);
}
}
}
});
await FireStoreUtils.getStory().then((stories) {
storyList.clear();
print("Total stories fetched: ${stories.length}");
// Create a fast lookup Set of all nearest vendor IDs
final nearestIds = allNearestRestaurant.map((e) => e.id).toSet();
print("nearestIds: $nearestIds");
// Filter stories whose vendorID exists in nearestIds
storyList.addAll(
stories.where((story) => nearestIds.contains(story.vendorID))
);
print("Filtered storyList length: ${storyList.length}");
});
if (Constant.isEnableAdsFeature == true) {
await FireStoreUtils.getAllAdvertisement().then((value) {
advertisementList.clear();
for (var element1 in value) {
for (var element in allNearestRestaurant) {
if (element1.vendorId == element.id) {
advertisementList.add(element1);
}
}
}
});
}
});
setLoading();
}
Future<void> setLoading() async {
await Future.delayed(Duration(seconds: 1), () async {
if (allNearestRestaurant.isEmpty) {
await Future.delayed(Duration(seconds: 2), () {
isLoading.value = false;
});
} else {
isLoading.value = false;
}
update();
});
}
Future<void> getVendorCategory() async {
await FireStoreUtils.getHomeVendorCategory().then((value) {
vendorCategoryModel.value = value;
if (Constant.restaurantList != null) {
List<String> usedCategoryIds = Constant.restaurantList!.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
}
});
await FireStoreUtils.getHomeTopBanner().then((value) {
bannerModel.value = value;
});
await FireStoreUtils.getHomeBottomBanner().then((value) {
bannerBottomModel.value = value;
});
await getFavouriteRestaurant();
}
Future<void> getFavouriteRestaurant() async {
if (Constant.userModel?.id != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
}
log("Constant.userModel?.id :: ${favouriteList.length}");
}
Future<void> getZone() async {
await FireStoreUtils.getZone().then((value) {
if (value != null) {
for (int i = 0; i < value.length; i++) {
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location?.latitude ?? 0.0, Constant.selectedLocation.location?.longitude ?? 0.0), value[i].area!)) {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = true;
break;
} else {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = false;
}
}
}
});
}
}

View File

@@ -0,0 +1,40 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../themes/show_toast_dialog.dart';
class ForgotPasswordController extends GetxController {
Rx<TextEditingController> emailEditingController =
TextEditingController().obs;
Future<void> forgotPassword() async {
final email = emailEditingController.value.text.trim();
if (email.isEmpty) {
ShowToastDialog.showToast("Please enter your email address.".tr);
return;
}
if (!GetUtils.isEmail(email)) {
ShowToastDialog.showToast("Please enter a valid email address.".tr);
return;
}
try {
ShowToastDialog.showLoader("Please wait...".tr);
await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
ShowToastDialog.closeLoader();
ShowToastDialog.showToast(
'reset_password_link_sent'.trParams({'email': email}),
);
Get.back();
} on FirebaseAuthException catch (e) {
ShowToastDialog.closeLoader();
if (e.code == 'user-not-found') {
ShowToastDialog.showToast('No user found for that email.'.tr);
} else {
ShowToastDialog.showToast(e.message?.tr ?? "something_went_wrong".tr);
}
}
}
}

View File

@@ -0,0 +1,920 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as maths;
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/gift_cards_model.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../models/gift_cards_order_model.dart';
import '../models/payment_model/cod_setting_model.dart';
import '../models/payment_model/flutter_wave_model.dart';
import '../models/payment_model/mercado_pago_model.dart';
import '../models/payment_model/mid_trans.dart';
import '../models/payment_model/orange_money.dart';
import '../models/payment_model/pay_fast_model.dart';
import '../models/payment_model/pay_stack_model.dart';
import '../models/payment_model/paypal_model.dart';
import '../models/payment_model/paytm_model.dart';
import '../models/payment_model/razorpay_model.dart';
import '../models/payment_model/stripe_model.dart';
import '../models/payment_model/wallet_setting_model.dart';
import '../models/payment_model/xendit.dart';
import '../models/user_model.dart';
import '../models/wallet_transaction_model.dart';
import '../payment/MercadoPagoScreen.dart';
import '../payment/PayFastScreen.dart';
import '../payment/getPaytmTxtToken.dart';
import '../payment/midtrans_screen.dart';
import '../payment/orangePayScreen.dart';
import '../payment/paystack/pay_stack_screen.dart';
import '../payment/paystack/pay_stack_url_model.dart';
import '../payment/paystack/paystack_url_genrater.dart';
import '../payment/stripe_failed_model.dart';
import '../payment/xenditModel.dart';
import '../payment/xenditScreen.dart';
import '../screen_ui/multi_vendor_service/gift_card/history_gift_card.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../service/fire_store_utils.dart';
import 'package:customer/utils/preferences.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
import '../themes/show_toast_dialog.dart';
class GiftCardController extends GetxController {
RxBool isLoading = true.obs;
RxString selectedPaymentMethod = ''.obs;
var pageController = PageController();
@override
void onInit() {
// TODO: implement onInit
getGiftCard();
super.onInit();
}
List<GiftCardsModel> giftCardList = [];
Rx<GiftCardsModel> selectedGiftCard = GiftCardsModel().obs;
List amountList = ["1000", "2000", "5000"];
RxString selectedAmount = "1000".obs;
var selectedPageIndex = 0.obs;
Rx<TextEditingController> amountController = TextEditingController().obs;
Rx<TextEditingController> messageController = TextEditingController().obs;
Rx<UserModel> userModel = UserModel().obs;
Future<void> getGiftCard() async {
await FireStoreUtils.getGiftCard().then((value) {
giftCardList = value;
if (giftCardList.isNotEmpty) {
selectedGiftCard.value = giftCardList.first;
messageController.value.text = selectedGiftCard.value.message.toString();
}
});
isLoading.value = false;
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then(
(value) {
if (value != null) {
userModel.value = value;
}
},
);
await getPaymentSettings();
}
Future<void> placeOrder() async {
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
if (double.parse(userModel.value.walletAmount.toString()) >= double.parse(amountController.value.text)) {
setOrder();
} else {
ShowToastDialog.showToast("You don't have sufficient wallet balance to purchase gift card".tr);
}
} else {
setOrder();
}
}
Future<void> setOrder() async {
ShowToastDialog.showLoader("Please wait...".tr);
GiftCardsOrderModel giftCardsOrderModel = GiftCardsOrderModel();
giftCardsOrderModel.id = const Uuid().v4();
giftCardsOrderModel.giftId = selectedGiftCard.value.id.toString();
giftCardsOrderModel.giftTitle = selectedGiftCard.value.title.toString();
giftCardsOrderModel.price = amountController.value.text;
giftCardsOrderModel.redeem = false;
giftCardsOrderModel.message = messageController.value.text;
giftCardsOrderModel.giftPin = generateGiftPin();
giftCardsOrderModel.giftCode = generateGiftCode();
giftCardsOrderModel.paymentType = selectedPaymentMethod.value;
giftCardsOrderModel.createdDate = Timestamp.now();
DateTime dateTime = DateTime.now().add(Duration(days: int.parse(selectedGiftCard.value.expiryDay ?? "2")));
giftCardsOrderModel.expireDate = Timestamp.fromDate(dateTime);
giftCardsOrderModel.userid = FireStoreUtils.getCurrentUid();
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(amountController.value.text),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "user",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: giftCardsOrderModel.id,
note: "Gift card purchase amount debited".tr,
paymentStatus: "success".tr);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${amountController.value.text.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
}
});
}
await FireStoreUtils.placeGiftCardOrder(giftCardsOrderModel);
ShowToastDialog.closeLoader();
Get.off(const HistoryGiftCard());
ShowToastDialog.showToast("Gift card Purchases successfully".tr);
}
String generateGiftCode() {
var rng = Random();
String generatedNumber = '';
for (int i = 0; i < 16; i++) {
generatedNumber += (rng.nextInt(9) + 1).toString();
}
return generatedNumber;
}
String generateGiftPin() {
var rng = Random();
String generatedNumber = '';
for (int i = 0; i < 6; i++) {
generatedNumber += (rng.nextInt(9) + 1).toString();
}
return generatedNumber;
}
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then(
(value) {
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
}else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'GoRide';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
},
);
}
// final _flutterPaypalNativePlugin = FlutterPaypalNative.instance;
// void initPayPal() async {
// //set debugMode for error logging
// FlutterPaypalNative.isDebugMode = paytmModel.value.isSandboxEnabled == true ? true : false;
// //initiate payPal plugin
// await _flutterPaypalNativePlugin.init(
// //your app id !!! No Underscore!!! see readme.md for help
// returnUrl: "com.parkme://paypalpay",
// //client id from developer dashboard
// clientID: payPalModel.value.paypalClient.toString(),
// //sandbox, staging, live etc
// payPalEnvironment: payPalModel.value.isLive == false ? FPayPalEnvironment.sandbox : FPayPalEnvironment.live,
// //what currency do you plan to use? default is US dollars
// currencyCode: FPayPalCurrencyCode.usd,
// //action paynow?
// action: FPayPalUserAction.payNow,
// );
// //call backs for payment
// _flutterPaypalNativePlugin.setPayPalOrderCallback(
// callback: FPayPalOrderCallback(
// onCancel: () {
// //user canceled the payment
// ShowToastDialog.showToast("Payment canceled");
// },
// onSuccess: (data) {
// //successfully paid
// //remove all items from queue
// // _flutterPaypalNativePlugin.removeAllPurchaseItems();
// ShowToastDialog.showToast("Payment Successful!!");
// placeOrder();
// },
// onError: (data) {
// //an error occured
// ShowToastDialog.showToast("error: ${data.reason}");
// },
// onShippingChange: (data) {
// //the user updated the shipping address
// ShowToastDialog.showToast("shipping change: ${data.shippingChangeAddress?.adminArea1 ?? ""}");
// },
// ),
// );
// }
// paypalPaymentSheet(String amount) {
// //add 1 item to cart. Max is 4!
// if (_flutterPaypalNativePlugin.canAddMorePurchaseUnit) {
// _flutterPaypalNativePlugin.addPurchaseUnit(
// FPayPalPurchaseUnit(
// // random prices
// amount: double.parse(amount),
// ///please use your own algorithm for referenceId. Maybe ProductID?
// referenceId: FPayPalStrHelper.getRandomString(16),
// ),
// );
// }
// // initPayPal();
// _flutterPaypalNativePlugin.makeOrder(
// action: FPayPalUserAction.payNow,
// );
// }
// Strip
Future<void> stripeMakePayment({required String amount}) async {
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.");
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(
merchantCountryCode: 'US',
testEnv: true,
currencyCode: "USD",
),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(
colors: PaymentSheetAppearanceColors(
primary: AppThemeData.primary300,
),
),
merchantDisplayName: 'GoRide'));
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": userModel.value.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body, headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'});
return jsonDecode(response.body);
} catch (e) {
print(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {
'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}',
'Content-Type': 'application/json',
};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
}
],
"payer": {"email": userModel.value.email},
"back_urls": {
"failure": "${Constant.globalUrl}payment/failure",
"pending": "${Constant.globalUrl}payment/pending",
"success": "${Constant.globalUrl}payment/success",
},
"auto_return": "approved" // Automatically return after payment is approved
});
final response = await http.post(
Uri.parse("https://api.mercadopago.com/checkout/preferences"),
headers: headers,
body: body,
);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Error creating preference: ${response.body}');
return null;
}
}
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
await PayStackURLGen.payStackURLGen(
amount: (double.parse(totalAmount) * 100).toString(), currency: "ZAR", secretKey: payStackModel.value.secretKey.toString(), userModel: userModel.value)
.then((value) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
))!
.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
//flutter wave Payment Method
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {
'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}',
'Content-Type': 'application/json',
};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {
"email": userModel.value.email.toString(),
"phonenumber": userModel.value.phoneNumber, // Add a real phone number
"name": userModel.value.fullName(), // Add a real customer name
},
"customizations": {
"title": "Payment for Services",
"description": "Payment for XYZ services",
}
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Payment initialization failed: ${response.body}');
return null;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: userModel.value).then((String? value) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
//PayPal
void paypalPaymentSheet(String amount, context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.parkme://paypalpay",
cancelURL: "com.parkme://paypalpay",
transactions: [
{
"amount": {
"total": amount,
"currency": "USD",
"details": {"subtotal": amount}
},
}
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
placeOrder();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}),
),
);
}
///Paytm payment function
Future<void> getPaytmCheckSum(context, {required double amount}) async {
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
final response = await http.post(
Uri.parse(
getChecksum,
),
headers: {},
body: {
"mid": paytmModel.value.paytmMID.toString(),
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
});
final data = jsonDecode(response.body);
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
initiatePayment(amount: amount, orderId: orderId).then((value) {
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
GetPaymentTxtTokenModel result = value;
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
});
});
}
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
// try {
// var response = AllInOneSdk.startTransaction(
// paytmModel.value.paytmMID.toString(),
// orderId,
// amount.toString(),
// txnTokenBy,
// callBackURL,
// isStaging,
// true,
// true,
// );
//
// response.then((value) {
// if (value!["RESPMSG"] == "Txn Success") {
// ShowToastDialog.showToast("Payment Successful!!");
// placeOrder();
// }
// }).catchError((onError) {
// if (onError is PlatformException) {
// Get.back();
//
// ShowToastDialog.showToast(onError.message.toString());
// } else {
// print("======>>2");
// Get.back();
// ShowToastDialog.showToast(onError.message.toString());
// }
// });
// } catch (err) {
// Get.back();
// ShowToastDialog.showToast(err.toString());
// }
}
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
final response = await http.post(
Uri.parse(
getChecksum,
),
headers: {},
body: {
"mid": paytmModel.value.paytmMID.toString(),
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
"checksum_value": checkSum,
});
final data = jsonDecode(response.body);
return data['status'];
}
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
final response = await http.post(Uri.parse(initiateURL), headers: {}, body: {
"mid": paytmModel.value.paytmMID,
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
"amount": amount.toString(),
"currency": "INR",
"callback_url": callback,
"custId": FireStoreUtils.getCurrentUid(),
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
});
print(response.body);
final data = jsonDecode(response.body);
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
Get.back();
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
}
return GetPaymentTxtTokenModel.fromJson(data);
}
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {
'contact': userModel.value.phoneNumber,
'email': userModel.value.email,
},
'external': {
'wallets': ['paytm']
}
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(
initialURl: url,
))!
.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
final response = await http.post(
url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!),
},
body: jsonEncode({
'transaction_details': {
'order_id': ordersId,
'gross_amount': double.parse(amount.toString()).toInt(),
},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
//Orangepay payment
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString() != '') {
Get.to(() => OrangeMoneyScreen(
initialURl: paymentURL,
accessToken: accessToken,
amount: amount,
orangePay: orangeMoneyModel.value,
orderId: orderId,
payToken: payToken,
))!
.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
}
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
String apiUrl = 'https://api.orange.com/oauth/v3/token';
Map<String, String> requestBody = {
'grant_type': 'client_credentials',
};
var response = await http.post(Uri.parse(apiUrl),
headers: <String, String>{
'Authorization': "Basic ${orangeMoneyModel.value.auth!}",
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
},
body: requestBody);
// Handle the response
if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'];
// ignore: use_build_context_synchronously
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
orderId = orderIdData;
amount = amountData;
String apiUrl =
orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
"order_id": orderId,
"amount": amount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
// Handle the response
if (response.statusCode == 201) {
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'];
return responseData['payment_url'];
} else {
return '';
}
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
orderId = '';
amount = '';
}
//XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(() => XenditScreen(
initialURl: model.invoiceUrl ?? '',
transId: model.id ?? '',
apiKey: xenditModel.value.apiKey!.toString(),
))!
.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

View File

@@ -0,0 +1,48 @@
import 'dart:developer';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/currency_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/utils/notification_service.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
import '../constant/collection_name.dart';
import '../service/fire_store_utils.dart';
class GlobalSettingController extends GetxController {
@override
void onInit() {
notificationInit();
getCurrentCurrency();
super.onInit();
}
Future<void> getCurrentCurrency() async {
FireStoreUtils.fireStore.collection(CollectionName.currencies).where("isActive", isEqualTo: true).snapshots().listen((event) {
if (event.docs.isNotEmpty) {
Constant.currencyModel = CurrencyModel.fromJson(event.docs.first.data());
} else {
Constant.currencyModel = CurrencyModel(id: "", code: "USD", decimal: 2, isactive: true, name: "US Dollar", symbol: "\$", symbolatright: false);
}
});
await FireStoreUtils.getSettings();
}
NotificationService notificationService = NotificationService();
void notificationInit() {
notificationService.initInfo().then((value) async {
String token = await NotificationService.getToken();
log(":::::::TOKEN:::::: $token");
if (FirebaseAuth.instance.currentUser != null) {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
if (value != null) {
UserModel driverUserModel = value;
driverUserModel.fcmToken = token;
FireStoreUtils.updateUser(driverUserModel);
}
});
}
});
}
}

View File

@@ -0,0 +1,38 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/gift_cards_order_model.dart';
import 'package:share_plus/share_plus.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class HistoryGiftCardController extends GetxController {
RxList<GiftCardsOrderModel> giftCardsOrderList = <GiftCardsOrderModel>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
getData();
super.onInit();
}
Future<void> getData() async {
await FireStoreUtils.getGiftHistory().then((value) {
giftCardsOrderList.value = value;
});
isLoading.value = false;
}
void updateList(int index) {
GiftCardsOrderModel giftCardsOrderModel = giftCardsOrderList[index];
giftCardsOrderModel.isPasswordShow = giftCardsOrderModel.isPasswordShow == true ? false : true;
giftCardsOrderList.removeAt(index);
giftCardsOrderList.insert(index, giftCardsOrderModel);
}
Future<void> share(String giftCode, String giftPin, String msg, String amount, Timestamp date) async {
await Share.share(
"${'Gift Code :'.tr} $giftCode\n${'Gift Pin :'.tr} $giftPin\n${'Price :'.tr} ${Constant.amountShow(amount: amount)}\n${'Expire Date :'.tr} ${date.toDate()}\n\n${'Message'.tr} : $msg",
);
}
}

View File

@@ -0,0 +1,132 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/advertisement_model.dart';
import 'package:customer/models/banner_model.dart';
import 'package:customer/models/brands_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/service/cart_provider.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/constant.dart';
class HomeECommerceController extends GetxController {
final CartProvider cartProvider = CartProvider();
Future<void> getCartData() async {
cartProvider.cartStream.listen((event) async {
cartItem.clear();
cartItem.addAll(event);
});
update();
}
RxBool isLoading = true.obs;
RxBool isListView = true.obs;
RxBool isPopular = true.obs;
Rx<PageController> pageController = PageController(viewportFraction: 0.877).obs;
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
RxInt currentPage = 0.obs;
RxInt currentBottomPage = 0.obs;
@override
void onInit() {
// TODO: implement onInit
getVendorCategory();
getData();
super.onInit();
}
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
RxList<VendorCategoryModel> categoryWiseProductList = <VendorCategoryModel>[].obs;
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
RxList<BannerModel> bannerModel = <BannerModel>[].obs;
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
RxList<BrandsModel> brandList = <BrandsModel>[].obs;
Future<void> getData() async {
isLoading.value = true;
getCartData();
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
print("=====>${event.length}");
newArrivalRestaurantList.clear();
allNearestRestaurant.clear();
advertisementList.clear();
allNearestRestaurant.addAll(event);
newArrivalRestaurantList.addAll(event);
Constant.restaurantList = allNearestRestaurant;
List<String> usedCategoryIds = allNearestRestaurant.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
newArrivalRestaurantList.sort((a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()));
if (Constant.isEnableAdsFeature == true) {
await FireStoreUtils.getAllAdvertisement().then((value) {
advertisementList.clear();
for (var element1 in value) {
for (var element in allNearestRestaurant) {
if (element1.vendorId == element.id) {
advertisementList.add(element1);
}
}
}
});
}
});
setLoading();
}
Future<void> setLoading() async {
await Future.delayed(Duration(seconds: 1), () async {
if (allNearestRestaurant.isEmpty) {
await Future.delayed(Duration(seconds: 2), () {
isLoading.value = false;
});
} else {
isLoading.value = false;
}
update();
});
}
Future<void> getVendorCategory() async {
await FireStoreUtils.getHomeVendorCategory().then((value) {
vendorCategoryModel.value = value;
});
await FireStoreUtils.getHomePageShowCategory().then((value) {
categoryWiseProductList.value = value;
});
await FireStoreUtils.getHomeTopBanner().then((value) {
bannerModel.value = value;
});
await FireStoreUtils.getHomeBottomBanner().then((value) {
bannerBottomModel.value = value;
});
await FireStoreUtils.getBrandList().then((value) {
brandList.value = value;
});
await getFavouriteRestaurant();
}
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
Future<void> getFavouriteRestaurant() async {
if (Constant.userModel?.id != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
}
}
}

View File

@@ -0,0 +1,42 @@
import 'dart:developer';
import 'package:get/get.dart';
import '../models/banner_model.dart';
import '../models/parcel_category.dart';
import '../service/fire_store_utils.dart';
class HomeParcelController extends GetxController {
RxBool isLoading = true.obs;
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
RxList<ParcelCategory> parcelCategory = <ParcelCategory>[].obs;
@override
void onInit() {
super.onInit();
loadData();
}
void loadData() async {
try {
isLoading.value = true;
// Load banners
await FireStoreUtils.getHomeTopBanner().then((value) {
bannerTopHome.value = value;
log('Banners loaded: ${bannerTopHome.length}');
});
// Load parcel categories
await FireStoreUtils.getParcelServiceCategory().then((value) {
parcelCategory.value = value;
log('Parcel categories loaded: ${parcelCategory.length}');
});
} catch (e) {
bannerTopHome.clear();
parcelCategory.clear();
} finally {
isLoading.value = false;
}
}
}

View File

@@ -0,0 +1,256 @@
import 'dart:async';
import 'dart:convert';
import 'package:customer/constant/collection_name.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/order_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:latlong2/latlong.dart' as location;
import 'package:flutter_map/flutter_map.dart' as flutterMap;
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:http/http.dart' as http;
class LiveTrackingController extends GetxController {
GoogleMapController? mapController;
final flutterMap.MapController osmMapController = flutterMap.MapController();
Rx<OrderModel> orderModel = OrderModel().obs;
Rx<UserModel> driverUserModel = UserModel().obs;
RxBool isLoading = true.obs;
Rx<location.LatLng> source = location.LatLng(0, 0).obs;
Rx<location.LatLng> destination = location.LatLng(0, 0).obs;
Rx<location.LatLng> driverCurrent = location.LatLng(0, 0).obs;
RxList<location.LatLng> routePoints = <location.LatLng>[].obs;
RxMap<MarkerId, Marker> markers = <MarkerId, Marker>{}.obs;
RxMap<PolylineId, Polyline> polyLines = <PolylineId, Polyline>{}.obs;
RxList<flutterMap.Marker> osmMarkers = <flutterMap.Marker>[].obs;
BitmapDescriptor? pickupIcon;
BitmapDescriptor? dropoffIcon;
BitmapDescriptor? driverIcon;
PolylinePoints polylinePoints = PolylinePoints(apiKey: Constant.mapAPIKey);
StreamSubscription? orderSub;
StreamSubscription? driverSub;
@override
void onInit() {
super.onInit();
addMarkerIcons();
getArguments();
}
@override
void onClose() {
orderSub?.cancel();
driverSub?.cancel();
super.onClose();
}
Future<void> getArguments() async {
final args = Get.arguments;
if (args == null) return;
orderModel.value = args['orderModel'];
orderSub = FireStoreUtils.fireStore.collection(CollectionName.vendorOrders).doc(orderModel.value.id).snapshots().listen((orderSnap) {
if (orderSnap.data() == null) return;
orderModel.value = OrderModel.fromJson(orderSnap.data()!);
if (orderModel.value.driverID != null) {
driverSub?.cancel();
driverSub = FireStoreUtils.fireStore.collection(CollectionName.users).doc(orderModel.value.driverID).snapshots().listen((driverSnap) async {
if (driverSnap.data() == null) return;
driverUserModel.value = UserModel.fromJson(driverSnap.data()!);
await updateLiveTracking();
});
}
if (orderModel.value.status == Constant.orderCompleted) {
Get.back();
}
});
isLoading.value = false;
}
Future<void> updateLiveTracking() async {
driverCurrent.value = location.LatLng(driverUserModel.value.location?.latitude ?? 0.0, driverUserModel.value.location?.longitude ?? 0.0);
source.value = location.LatLng(orderModel.value.vendor?.latitude ?? 0.0, orderModel.value.vendor?.longitude ?? 0.0);
destination.value = location.LatLng(orderModel.value.address?.location?.latitude ?? 0.0, orderModel.value.address?.location?.longitude ?? 0.0);
if (orderModel.value.status == Constant.orderPlaced || orderModel.value.status == Constant.orderAccepted) {
await showDriverToRestaurantRoute();
} else if (orderModel.value.status == Constant.orderShipped || orderModel.value.status == Constant.orderInTransit) {
await showDriverToCustomerRoute();
}
}
Future<void> showDriverToRestaurantRoute() async {
clearOldData();
if (Constant.selectedMapType == 'osm') {
await fetchRoute(driverCurrent.value, source.value);
addOsmMarkers(showPickup: true, showDrop: false);
animateToOSMLocation(driverCurrent.value);
} else {
await getPolyline(
sourceLatitude: driverCurrent.value.latitude,
sourceLongitude: driverCurrent.value.longitude,
destinationLatitude: source.value.latitude,
destinationLongitude: source.value.longitude,
showPickup: true,
showDrop: false,
);
}
}
Future<void> showDriverToCustomerRoute() async {
clearOldData();
if (Constant.selectedMapType == 'osm') {
await fetchRoute(driverCurrent.value, destination.value);
addOsmMarkers(showPickup: false, showDrop: true);
animateToOSMLocation(driverCurrent.value);
} else {
await getPolyline(
sourceLatitude: driverCurrent.value.latitude,
sourceLongitude: driverCurrent.value.longitude,
destinationLatitude: destination.value.latitude,
destinationLongitude: destination.value.longitude,
showPickup: false,
showDrop: true,
);
}
}
void clearOldData() {
markers.clear();
polyLines.clear();
routePoints.clear();
}
Future<void> fetchRoute(location.LatLng source, location.LatLng destination) async {
final url = Uri.parse(
'https://router.project-osrm.org/route/v1/driving/${source.longitude},${source.latitude};${destination.longitude},${destination.latitude}?overview=full&geometries=geojson',
);
final response = await http.get(url);
if (response.statusCode == 200) {
final data = json.decode(response.body);
final coords = data['routes'][0]['geometry']['coordinates'];
routePoints.value = coords.map<location.LatLng>((c) => location.LatLng(c[1].toDouble(), c[0].toDouble())).toList();
}
}
void animateToOSMLocation(location.LatLng loc) {
osmMapController.move(loc, 15);
}
void addOsmMarkers({bool showPickup = false, bool showDrop = false}) {
final List<flutterMap.Marker> tempMarkers = [
// Driver Marker
flutterMap.Marker(point: driverCurrent.value, width: 40, height: 40, child: Image.asset('assets/images/food_delivery.png')),
];
if (showPickup) {
tempMarkers.add(flutterMap.Marker(point: source.value, width: 40, height: 40, child: Image.asset('assets/images/pickup.png')));
}
if (showDrop) {
tempMarkers.add(flutterMap.Marker(point: destination.value, width: 40, height: 40, child: Image.asset('assets/images/dropoff.png')));
}
osmMarkers.value = tempMarkers;
}
Future<void> getPolyline({
required double sourceLatitude,
required double sourceLongitude,
required double destinationLatitude,
required double destinationLongitude,
bool showPickup = false,
bool showDrop = false,
}) async {
List<LatLng> polylineCoordinates = [];
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
request: PolylineRequest(origin: PointLatLng(sourceLatitude, sourceLongitude), destination: PointLatLng(destinationLatitude, destinationLongitude), mode: TravelMode.driving),
);
if (result.points.isNotEmpty) {
polylineCoordinates = result.points.map((e) => LatLng(e.latitude, e.longitude)).toList();
}
addGoogleMarkers(showPickup: showPickup, showDrop: showDrop);
_addPolyLine(polylineCoordinates);
}
void addGoogleMarkers({bool showPickup = false, bool showDrop = false}) {
markers.clear();
// Always show driver marker
if (driverUserModel.value.location != null && driverIcon != null) {
addMarker(
id: "Driver",
latitude: driverUserModel.value.location?.latitude ?? 0.0,
longitude: driverUserModel.value.location?.longitude ?? 0.0,
descriptor: driverIcon!,
rotation: (driverUserModel.value.rotation ?? 0).toDouble(),
);
}
if (showPickup && orderModel.value.vendor?.latitude != null && pickupIcon != null) {
addMarker(id: "Pickup", latitude: orderModel.value.vendor!.latitude ?? 0.0, longitude: orderModel.value.vendor!.longitude ?? 0.0, descriptor: pickupIcon!, rotation: 0.0);
} else if (showDrop && orderModel.value.address?.location?.latitude != null && dropoffIcon != null) {
addMarker(
id: "Drop",
latitude: orderModel.value.address!.location!.latitude ?? 0.0,
longitude: orderModel.value.address!.location!.longitude ?? 0.0,
descriptor: dropoffIcon!,
rotation: 0.0,
);
}
}
void addMarker({required String id, required double latitude, required double longitude, required BitmapDescriptor descriptor, required double rotation}) {
MarkerId markerId = MarkerId(id);
markers[markerId] = Marker(markerId: markerId, icon: descriptor, position: LatLng(latitude, longitude), rotation: rotation, anchor: const Offset(0.5, 0.5));
}
Future<void> addMarkerIcons() async {
if (Constant.selectedMapType == 'osm') return;
pickupIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/pickup.png', 100));
dropoffIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/dropoff.png', 100));
driverIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/food_delivery.png', 100));
}
Future<void> _addPolyLine(List<LatLng> polylineCoordinates) async {
if (polylineCoordinates.isEmpty) return;
PolylineId id = const PolylineId("poly");
Polyline polyline = Polyline(polylineId: id, color: Colors.blue, width: 5, points: polylineCoordinates);
polyLines[id] = polyline;
await updateCameraBounds(polylineCoordinates);
}
Future<void> updateCameraBounds(List<LatLng> points) async {
if (mapController == null || points.isEmpty) return;
double minLat = points.map((e) => e.latitude).reduce((a, b) => a < b ? a : b);
double maxLat = points.map((e) => e.latitude).reduce((a, b) => a > b ? a : b);
double minLng = points.map((e) => e.longitude).reduce((a, b) => a < b ? a : b);
double maxLng = points.map((e) => e.longitude).reduce((a, b) => a > b ? a : b);
LatLngBounds bounds = LatLngBounds(southwest: LatLng(minLat, minLng), northeast: LatLng(maxLat, maxLng));
await mapController!.animateCamera(CameraUpdate.newLatLngBounds(bounds, 80));
}
}

View File

@@ -0,0 +1,273 @@
import 'dart:convert';
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import '../constant/constant.dart';
import '../models/user_model.dart';
import '../screen_ui/auth_screens/login_screen.dart';
import '../screen_ui/auth_screens/sign_up_screen.dart';
import '../screen_ui/service_home_screen/service_list_screen.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
import '../utils/notification_service.dart';
import 'package:crypto/crypto.dart';
class LoginController extends GetxController {
Rx<TextEditingController> emailController = TextEditingController().obs;
Rx<TextEditingController> passwordController = TextEditingController().obs;
/// Focus nodes
final FocusNode emailFocusNode = FocusNode();
final FocusNode passwordFocusNode = FocusNode();
/// Loading indicator
final RxBool isLoading = false.obs;
RxBool passwordVisible = true.obs;
Future<void> loginWithEmail() async {
final email = emailController.value.text.trim();
final password = passwordController.value.text.trim();
if (email.isEmpty || !email.contains('@')) {
ShowToastDialog.showToast("Please enter a valid email address".tr);
return;
}
if (password.isEmpty) {
ShowToastDialog.showToast("Please enter your password".tr);
return;
}
try {
isLoading.value = true;
ShowToastDialog.showLoader("Logging in...".tr);
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
final userModel = await FireStoreUtils.getUserProfile(credential.user!.uid);
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
if (userModel.active == true) {
userModel.fcmToken = await NotificationService.getToken();
await FireStoreUtils.updateUser(userModel);
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
final defaultAddress = userModel.shippingAddress!.firstWhere(
(e) => e.isDefault == true,
orElse: () => userModel.shippingAddress!.first,
);
Constant.selectedLocation = defaultAddress;
Get.offAll(() => const ServiceListScreen());
} else {
Get.offAll(() => const LocationPermissionScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
Get.offAll(() => const LoginScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
Get.offAll(() => const LoginScreen());
}
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
ShowToastDialog.showToast("No user found for that email.".tr);
} else if (e.code == 'wrong-password') {
ShowToastDialog.showToast("Wrong password provided.".tr);
} else if (e.code == 'invalid-email') {
ShowToastDialog.showToast("Invalid email.".tr);
} else {
ShowToastDialog.showToast(e.message?.tr ?? "Login failed. Please try again.".tr);
}
} finally {
isLoading.value = false;
ShowToastDialog.closeLoader();
}
}
Future<void> loginWithGoogle() async {
ShowToastDialog.showLoader("please wait...".tr);
await signInWithGoogle().then((value) async {
ShowToastDialog.closeLoader();
if (value != null) {
if (value.additionalUserInfo!.isNewUser) {
UserModel userModel = UserModel();
userModel.id = value.user!.uid;
userModel.email = value.user!.email;
userModel.firstName = value.user!.displayName?.split(' ').first;
userModel.lastName = value.user!.displayName?.split(' ').last;
userModel.provider = 'google';
ShowToastDialog.closeLoader();
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "google"});
} else {
await FireStoreUtils.userExistOrNot(value.user!.uid).then((userExit) async {
ShowToastDialog.closeLoader();
if (userExit == true) {
UserModel? userModel = await FireStoreUtils.getUserProfile(value.user!.uid);
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
if (userModel.active == true) {
userModel.fcmToken = await NotificationService.getToken();
await FireStoreUtils.updateUser(userModel);
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
final defaultAddress = userModel.shippingAddress!.firstWhere(
(e) => e.isDefault == true,
orElse: () => userModel.shippingAddress!.first,
);
Constant.selectedLocation = defaultAddress;
Get.offAll(() => const ServiceListScreen());
} else {
Get.offAll(() => const LocationPermissionScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
Get.offAll(() => const LoginScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
Get.offAll(() => const LoginScreen());
}
} else {
UserModel userModel = UserModel();
userModel.id = value.user!.uid;
userModel.email = value.user!.email;
userModel.firstName = value.user!.displayName?.split(' ').first;
userModel.lastName = value.user!.displayName?.split(' ').last;
userModel.provider = 'google';
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "google"});
}
});
}
}
});
}
Future<void> loginWithApple() async {
ShowToastDialog.showLoader("please wait...".tr);
await signInWithApple().then((value) async {
ShowToastDialog.closeLoader();
if (value != null) {
Map<String, dynamic> map = value;
AuthorizationCredentialAppleID appleCredential = map['appleCredential'];
UserCredential userCredential = map['userCredential'];
if (userCredential.additionalUserInfo!.isNewUser) {
// New user → go to sign-up
UserModel userModel = UserModel();
userModel.id = userCredential.user!.uid;
userModel.email = appleCredential.email;
userModel.firstName = appleCredential.givenName;
userModel.lastName = appleCredential.familyName;
userModel.provider = 'apple';
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "apple"});
} else {
// Existing user
await FireStoreUtils.userExistOrNot(userCredential.user!.uid).then((userExit) async {
if (userExit == true) {
UserModel? userModel = await FireStoreUtils.getUserProfile(userCredential.user!.uid);
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
if (userModel.active == true) {
userModel.fcmToken = await NotificationService.getToken();
await FireStoreUtils.updateUser(userModel);
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
final defaultAddress = userModel.shippingAddress!.firstWhere(
(e) => e.isDefault == true,
orElse: () => userModel.shippingAddress!.first,
);
Constant.selectedLocation = defaultAddress;
Get.offAll(() => const ServiceListScreen());
} else {
Get.offAll(() => const LocationPermissionScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
Get.offAll(() => const LoginScreen());
}
} else {
await FirebaseAuth.instance.signOut();
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
Get.offAll(() => const LoginScreen());
}
} else {
// User not in DB → go to signup
UserModel userModel = UserModel();
userModel.id = userCredential.user!.uid;
userModel.email = appleCredential.email;
userModel.firstName = appleCredential.givenName;
userModel.lastName = appleCredential.familyName;
userModel.provider = 'apple';
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "apple"});
}
});
}
}
});
}
Future<UserCredential?> signInWithGoogle() async {
try {
final GoogleSignIn googleSignIn = GoogleSignIn.instance;
await googleSignIn.initialize();
final GoogleSignInAccount googleUser = await googleSignIn.authenticate();
if (googleUser.id.isEmpty) return null;
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
final credential = GoogleAuthProvider.credential(idToken: googleAuth.idToken);
final userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
return userCredential;
} catch (e) {
print("Google Sign-In Error: $e");
return null;
}
}
String sha256ofString(String input) {
final bytes = utf8.encode(input);
final digest = sha256.convert(bytes);
return digest.toString();
}
Future<Map<String, dynamic>?> signInWithApple() async {
try {
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
AuthorizationCredentialAppleID appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName],
nonce: nonce,
);
final oauthCredential = OAuthProvider(
"apple.com",
).credential(idToken: appleCredential.identityToken, rawNonce: rawNonce, accessToken: appleCredential.authorizationCode);
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
return {"appleCredential": appleCredential, "userCredential": userCredential};
} catch (e) {
debugPrint(e.toString());
}
return null;
}
}

View File

@@ -0,0 +1,110 @@
import 'dart:typed_data';
import 'package:customer/constant/constant.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart' as flutterMap;
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:latlong2/latlong.dart' as location;
import '../screen_ui/multi_vendor_service/restaurant_details_screen/restaurant_details_screen.dart';
import 'food_home_controller.dart';
class MapViewController extends GetxController {
GoogleMapController? mapController;
BitmapDescriptor? parkingMarker;
BitmapDescriptor? currentLocationMarker;
FoodHomeController homeController = Get.find<FoodHomeController>();
Image? departureOsmIcon; //OSM
RxList<flutterMap.Marker> osmMarker = <flutterMap.Marker>[].obs;
final flutterMap.MapController osmMapController = flutterMap.MapController();
@override
void onInit() {
// TODO: implement onInit
addMarkerSetup();
super.onInit();
}
Future<void> addMarkerSetup() async {
if (Constant.selectedMapType == "osm") {
departureOsmIcon = Image.asset(
"assets/images/map_selected.png",
width: 30,
height: 30,
); //OSM
for (var element in homeController.allNearestRestaurant) {
osmMarker.add(
flutterMap.Marker(
point: location.LatLng(
element.latitude ?? 0.0,
element.longitude ?? 0.0,
),
width: 40,
height: 40,
child: GestureDetector(
onTap: () {
Get.to(
RestaurantDetailsScreen(),
arguments: {"vendorModel": element},
);
},
child: departureOsmIcon,
),
),
);
}
} else {
final Uint8List parking = await Constant().getBytesFromAsset(
"assets/images/map_selected.png",
20,
);
parkingMarker = BitmapDescriptor.bytes(parking);
for (var element in homeController.allNearestRestaurant) {
addMarker(
latitude: element.latitude,
longitude: element.longitude,
id: element.id.toString(),
rotation: 0,
descriptor: parkingMarker!,
title: element.title.toString(),
);
}
}
}
RxMap<MarkerId, Marker> markers = <MarkerId, Marker>{}.obs;
void addMarker({
required double? latitude,
required double? longitude,
required String id,
required BitmapDescriptor descriptor,
required double? rotation,
required String title,
}) {
MarkerId markerId = MarkerId(id);
Marker marker = Marker(
markerId: markerId,
icon: descriptor,
infoWindow: InfoWindow(
title: title,
onTap: () {
int index = homeController.allNearestRestaurant.indexWhere(
(p0) => p0.id == id,
);
Get.to(
const RestaurantDetailsScreen(),
arguments: {
"vendorModel": homeController.allNearestRestaurant[index],
},
);
},
),
position: LatLng(latitude ?? 0.0, longitude ?? 0.0),
rotation: rotation ?? 0.0,
);
markers[markerId] = marker;
}
}

View File

@@ -0,0 +1,63 @@
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/constant.dart';
import '../screen_ui/auth_screens/otp_verification_screen.dart';
class MobileLoginController extends GetxController {
final Rx<TextEditingController> mobileController = TextEditingController().obs;
final Rx<TextEditingController> countryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
final FirebaseAuth _auth = FirebaseAuth.instance;
/// Send OTP to the entered phone number
Future<void> sendOtp() async {
final mobile = mobileController.value.text.trim();
final countryCode = countryCodeController.value.text.trim();
if (mobile.isEmpty || mobile.length != 10) {
ShowToastDialog.showToast("Please enter a valid 10-digit mobile number".tr);
return;
}
try {
ShowToastDialog.showLoader("Sending OTP...".tr);
await _auth.verifyPhoneNumber(
phoneNumber: '$countryCode$mobile',
verificationCompleted: (PhoneAuthCredential credential) {
// Optionally handle auto-verification
},
verificationFailed: (FirebaseAuthException e) {
ShowToastDialog.closeLoader();
if (e.code == 'invalid-phone-number') {
ShowToastDialog.showToast("Invalid phone number".tr);
} else {
ShowToastDialog.showToast(e.message ?? "OTP verification failed".tr);
}
},
codeSent: (String verificationId, int? resendToken) {
ShowToastDialog.closeLoader();
Get.to(() => const OtpVerificationScreen(), arguments: {'countryCode': countryCode, 'phoneNumber': mobile, 'verificationId': verificationId});
},
codeAutoRetrievalTimeout: (String verificationId) {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("OTP timed out. Please try again.".tr);
// Optional: Handle timeout
},
);
} catch (e) {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Something went wrong. Please try again.".tr);
}
}
@override
void onClose() {
mobileController.value.dispose();
countryCodeController.value.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,73 @@
import 'package:get/get.dart';
import '../models/onprovider_order_model.dart';
import '../models/worker_model.dart';
import '../service/fire_store_utils.dart';
class MyBookingOnDemandController extends GetxController {
RxList<OnProviderOrderModel> orders = <OnProviderOrderModel>[].obs;
RxBool isLoading = true.obs;
RxString selectedTab = "Placed".obs;
RxMap<String, WorkerModel> workers = <String, WorkerModel>{}.obs;
RxList<String> tabTitles = ["Placed", "Completed", "Cancelled"].obs;
@override
void onInit() {
super.onInit();
listenOrders(); // Listen for real-time updates
}
void selectTab(String tab) {
selectedTab.value = tab;
}
void listenOrders() {
isLoading.value = true;
FireStoreUtils.getProviderOrdersStream().listen(
(updatedOrders) {
orders.value = updatedOrders;
// Fetch worker info if not already fetched
for (var order in updatedOrders) {
if (order.workerId != null && order.workerId!.isNotEmpty && !workers.containsKey(order.workerId!)) {
FireStoreUtils.getWorker(order.workerId!).then((worker) {
if (worker != null) workers[order.workerId!] = worker;
});
}
}
isLoading.value = false;
},
onError: (error) {
print("Error fetching orders stream: $error");
isLoading.value = false;
},
);
}
List<OnProviderOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
List<OnProviderOrderModel> getOrdersForTab(String tab) {
switch (tab) {
case "Placed":
return orders.where((order) => ["Order Placed", "Order Accepted", "Order Assigned", "Order Ongoing", "In Transit"].contains(order.status)).toList();
case "Completed":
return orders.where((order) => ["Order Completed"].contains(order.status)).toList();
case "Cancelled":
return orders.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
default:
return [];
}
}
WorkerModel? getWorker(String? workerId) {
if (workerId == null || workerId.isEmpty) return null;
return workers[workerId];
}
}

View File

@@ -0,0 +1,904 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as maths;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/cab_order_model.dart';
import 'package:customer/models/payment_model/cod_setting_model.dart';
import 'package:customer/models/payment_model/flutter_wave_model.dart';
import 'package:customer/models/payment_model/mercado_pago_model.dart';
import 'package:customer/models/payment_model/mid_trans.dart';
import 'package:customer/models/payment_model/orange_money.dart';
import 'package:customer/models/payment_model/pay_fast_model.dart';
import 'package:customer/models/payment_model/pay_stack_model.dart';
import 'package:customer/models/payment_model/paypal_model.dart';
import 'package:customer/models/payment_model/paytm_model.dart';
import 'package:customer/models/payment_model/razorpay_model.dart';
import 'package:customer/models/payment_model/stripe_model.dart';
import 'package:customer/models/payment_model/wallet_setting_model.dart';
import 'package:customer/models/payment_model/xendit.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:customer/payment/MercadoPagoScreen.dart';
import 'package:customer/payment/PayFastScreen.dart';
import 'package:customer/payment/getPaytmTxtToken.dart';
import 'package:customer/payment/midtrans_screen.dart';
import 'package:customer/payment/orangePayScreen.dart';
import 'package:customer/payment/paystack/pay_stack_screen.dart';
import 'package:customer/payment/paystack/pay_stack_url_model.dart';
import 'package:customer/payment/paystack/paystack_url_genrater.dart';
import 'package:customer/payment/stripe_failed_model.dart';
import 'package:customer/payment/xenditModel.dart';
import 'package:customer/payment/xenditScreen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:customer/utils/preferences.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:uuid/uuid.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../themes/app_them_data.dart';
class MyCabBookingController extends GetxController {
RxBool isLoading = true.obs;
RxString selectedTab = "New".obs;
RxList<CabOrderModel> cabOrder = <CabOrderModel>[].obs;
final List<String> tabKeys = ["New", "On Going", "Completed", "Cancelled"];
Rx<UserModel> userModel = UserModel().obs;
@override
Future<void> onInit() async {
super.onInit();
fetchParcelData();
}
Future<void> selectTab(String tab) async {
selectedTab.value = tab;
}
Future<void> fetchParcelData() async {
isLoading.value = true;
if (FirebaseAuth.instance.currentUser != null) {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((user) {
if (user != null) {
userModel.value = user;
}
});
FireStoreUtils.getCabDriverOrders().listen((orders) {
cabOrder.value = orders;
});
await getPaymentSettings();
}
isLoading.value = false;
}
List<CabOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
List<CabOrderModel> getOrdersForTab(String tab) {
switch (tab) {
case "New":
return cabOrder.where((order) => ["Order Placed", "Driver Pending"].contains(order.status)).toList();
case "On Going":
return cabOrder.where((order) => ["Driver Accepted", "Order Shipped", "In Transit"].contains(order.status)).toList();
case "Completed":
return cabOrder.where((order) => ["Order Completed"].contains(order.status)).toList();
case "Cancelled":
return cabOrder.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
default:
return [];
}
}
/// Get localized title for UI
String getLocalizedTabTitle(String tabKey) {
switch (tabKey) {
case "New":
return "New".tr;
case "On Going":
return "On Going".tr;
case "Completed":
return "Completed".tr;
case "Cancelled":
return "Cancelled".tr;
default:
return tabKey;
}
}
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
final RxString selectedPaymentMethod = ''.obs;
Rx<CabOrderModel> currentOrder = CabOrderModel().obs;
Rx<CabOrderModel> selectedOrder = CabOrderModel().obs;
RxDouble totalAmount = 0.0.obs;
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
void calculateTotalAmount(CabOrderModel order) {
subTotal.value = 0.0;
discount.value = 0.0;
taxAmount.value = 0.0;
totalAmount.value = 0.0;
selectedOrder.value = order;
try {
subTotal.value = double.tryParse(selectedOrder.value.subTotal?.toString() ?? "0") ?? 0.0;
discount.value = double.tryParse(selectedOrder.value.discount?.toString() ?? "0") ?? 0.0;
taxAmount.value = 0.0;
subTotal.value = subTotal.value;
if (selectedOrder.value.taxSetting != null) {
for (var element in selectedOrder.value.taxSetting!) {
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
}
}
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
} catch (e) {
ShowToastDialog.showToast("Failed to calculate total: $e");
}
}
Future<void> completeOrder() async {
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
await FireStoreUtils.cabOrderPlace(selectedOrder.value).then((value) {
ShowToastDialog.showToast("Payment method changed".tr);
Get.back();
});
} else {
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
userModel.value.inProgressOrderID ??= [];
userModel.value.inProgressOrderID!.clear();
await FireStoreUtils.updateUser(userModel.value);
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: selectedOrder.value.id,
note: "Cab Amount debited".tr,
paymentStatus: "success".tr,
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
});
}
selectedOrder.value.paymentStatus = true;
await FireStoreUtils.cabOrderPlace(selectedOrder.value).then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
Get.back();
});
}
}
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then((value) {
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.cod.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
} else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'eMart Customer';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
});
}
// Strip
Future<void> stripeMakePayment({required String amount}) async {
log(double.parse(amount).toStringAsFixed(0));
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
log("stripe Responce====>$paymentIntentData");
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
merchantDisplayName: 'GoRide',
),
);
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
log("$e \n$s");
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
completeOrder();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": Constant.userModel!.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
);
return jsonDecode(response.body);
} catch (e) {
log(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
},
],
"payer": {"email": Constant.userModel!.email},
"back_urls": {
"failure": "${Constant.globalUrl}payment/failure",
"pending": "${Constant.globalUrl}payment/pending",
"success": "${Constant.globalUrl}payment/success",
},
"auto_return": "approved",
// Automatically return after payment is approved
});
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Error creating preference: ${response.body}');
return null;
}
}
//Paypal
void paypalPaymentSheet(String amount, context) {
Navigator.of(context).push(
MaterialPageRoute(
builder:
(BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.parkme://paypalpay",
cancelURL: "com.parkme://paypalpay",
transactions: [
{
"amount": {
"total": amount,
"currency": "USD",
"details": {"subtotal": amount},
},
},
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
completeOrder();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
),
),
);
}
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
await PayStackURLGen.payStackURLGen(
amount: (double.parse(totalAmount) * 100).toString(),
currency: "ZAR",
secretKey: payStackModel.value.secretKey.toString(),
userModel: Constant.userModel!,
).then((value) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(
PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
),
)!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
//flutter wave Payment Method
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {
"email": Constant.userModel!.email.toString(),
"phonenumber": Constant.userModel!.phoneNumber, // Add a real phone number
"name": Constant.userModel!.fullName(), // Add a real customer name
},
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Payment initialization failed: ${response.body}');
return null;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((
String? value,
) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
completeOrder();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
///Paytm payment function
Future<void> getPaytmCheckSum(context, {required double amount}) async {
// final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
// String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
//
// final response = await http.post(
// Uri.parse(getChecksum),
// headers: {},
// body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
// );
//
// final data = jsonDecode(response.body);
// await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
// initiatePayment(amount: amount, orderId: orderId).then((value) {
// String callback = "";
// if (paytmModel.value.isSandboxEnabled == true) {
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// } else {
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// }
//
// GetPaymentTxtTokenModel result = value;
// startTransaction(context, txnTokenBy: result.body.txnToken, orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
// });
// });
}
Future<void> startTransaction(
context, {
required String txnTokenBy,
required orderId,
required double amount,
required callBackURL,
required isStaging,
}) async {
// try {
// var response = AllInOneSdk.startTransaction(
// paytmModel.value.paytmMID.toString(),
// orderId,
// amount.toString(),
// txnTokenBy,
// callBackURL,
// isStaging,
// true,
// true,
// );
//
// response.then((value) {
// if (value!["RESPMSG"] == "Txn Success") {
// print("txt done!!");
// ShowToastDialog.showToast("Payment Successful!!");
// completeOrder();
// }
// }).catchError((onError) {
// if (onError is PlatformException) {
// Get.back();
//
// ShowToastDialog.showToast(onError.message.toString());
// } else {
// log("======>>2");
// Get.back();
// ShowToastDialog.showToast(onError.message.toString());
// }
// });
// } catch (err) {
// Get.back();
// ShowToastDialog.showToast(err.toString());
// }
}
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {
"mid": paytmModel.value.paytmMID.toString(),
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
"checksum_value": checkSum,
},
);
final data = jsonDecode(response.body);
return data['status'];
}
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
final response = await http.post(
Uri.parse(initiateURL),
headers: {},
body: {
"mid": paytmModel.value.paytmMID,
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
"amount": amount.toString(),
"currency": "INR",
"callback_url": callback,
"custId": FireStoreUtils.getCurrentUid(),
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
},
);
log(response.body);
final data = jsonDecode(response.body);
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
Get.back();
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
}
return GetPaymentTxtTokenModel.fromJson(data);
}
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {'contact': Constant.userModel!.phoneNumber, 'email': Constant.userModel!.email},
'external': {
'wallets': ['paytm'],
},
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(
midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links',
);
final response = await http.post(
url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!),
},
body: jsonEncode({
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
//Orangepay payment
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString() != '') {
Get.to(
() => OrangeMoneyScreen(
initialURl: paymentURL,
accessToken: accessToken,
amount: amount,
orangePay: orangeMoneyModel.value,
orderId: orderId,
payToken: payToken,
),
)!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
}
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
String apiUrl = 'https://api.orange.com/oauth/v3/token';
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{
'Authorization': "Basic ${orangeMoneyModel.value.auth!}",
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
},
body: requestBody,
);
// Handle the response
if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'];
// ignore: use_build_context_synchronously
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future webpayment({
required String orderIdData,
required BuildContext context,
required String currency,
required String amountData,
}) async {
orderId = orderIdData;
amount = amountData;
String apiUrl =
orangeMoneyModel.value.isSandbox! == true
? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment'
: 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
"order_id": orderId,
"amount": amount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
// Handle the response
if (response.statusCode == 201) {
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'];
return responseData['payment_url'];
} else {
return '';
}
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
orderId = '';
amount = '';
}
//XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(
() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()),
)!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

View File

@@ -0,0 +1,51 @@
import 'dart:developer';
import 'package:customer/constant/constant.dart';
import 'package:customer/controllers/theme_controller.dart';
import '../service/fire_store_utils.dart';
import 'package:customer/utils/preferences.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
class MyProfileController extends GetxController {
RxBool isLoading = true.obs;
RxString isDarkMode = "Light".obs; // For UI text
RxBool isDarkModeSwitch = false.obs; // For switch widget
@override
void onInit() {
getTheme();
super.onInit();
}
void getTheme() {
bool isDark = Preferences.getBoolean(Preferences.themKey);
isDarkMode.value = isDark ? "Dark" : "Light";
isDarkModeSwitch.value = isDark;
isLoading.value = false;
}
void toggleDarkMode(bool value) {
isDarkModeSwitch.value = value;
isDarkMode.value = value ? "Dark" : "Light";
Preferences.setBoolean(Preferences.themKey, value);
// Update ThemeController for instant app theme change
if (Get.isRegistered<ThemeController>()) {
final themeController = Get.find<ThemeController>();
themeController.isDark.value = value;
}
}
// Delete user API
Future<bool> deleteUserFromServer() async {
var url = '${Constant.websiteUrl}/api/delete-user';
try {
var response = await http.post(Uri.parse(url), body: {'uuid': FireStoreUtils.getCurrentUid()});
log("deleteUserFromServer :: ${response.body}");
return response.statusCode == 200;
} catch (e) {
return false;
}
}
}

View File

@@ -0,0 +1,228 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:get/get.dart';
import '../models/rental_order_model.dart';
import '../models/tax_model.dart';
import '../service/fire_store_utils.dart';
class MyRentalBookingController extends GetxController {
RxBool isLoading = true.obs;
RxList<RentalOrderModel> rentalOrders = <RentalOrderModel>[].obs;
RxString selectedTab = "New".obs;
RxList<String> tabTitles = ["New", "On Going", "Completed", "Cancelled"].obs;
StreamSubscription<List<RentalOrderModel>>? _rentalSubscription;
final RxString selectedPaymentMethod = ''.obs;
@override
void onInit() {
super.onInit();
listenRentalOrders();
}
void selectTab(String tab) {
selectedTab.value = tab;
}
/// Start listening to rental orders live. Cancel previous subscription first.
void listenRentalOrders() {
isLoading.value = true;
_rentalSubscription?.cancel();
if (Constant.userModel != null) {
_rentalSubscription = FireStoreUtils.getRentalOrders().listen(
(orders) {
rentalOrders.assignAll(orders);
},
onError: (err) {
isLoading.value = false;
print("Error fetching rental orders: $err");
},
);
}
isLoading.value = false;
}
Rx<RentalOrderModel> selectedOrder = RentalOrderModel().obs;
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
RxDouble extraKilometerCharge = 0.0.obs;
RxDouble extraMinutesCharge = 0.0.obs;
void calculateTotalAmount(RentalOrderModel order) {
subTotal.value = 0.0;
discount.value = 0.0;
taxAmount.value = 0.0;
totalAmount.value = 0.0;
extraKilometerCharge.value = 0.0;
extraMinutesCharge.value = 0.0;
selectedOrder.value = order;
try {
subTotal.value = double.tryParse(selectedOrder.value.subTotal?.toString() ?? "0") ?? 0.0;
discount.value = double.tryParse(selectedOrder.value.discount?.toString() ?? "0") ?? 0.0;
taxAmount.value = 0.0;
if (selectedOrder.value.endTime != null) {
DateTime start = selectedOrder.value.startTime!.toDate();
DateTime end = selectedOrder.value.endTime!.toDate();
int hours = end.difference(start).inHours;
if (hours >= int.parse(selectedOrder.value.rentalPackageModel!.includedHours.toString())) {
hours = hours - int.parse(selectedOrder.value.rentalPackageModel!.includedHours.toString());
double hourlyRate = double.tryParse(selectedOrder.value.rentalPackageModel?.extraMinuteFare?.toString() ?? "0") ?? 0.0;
extraMinutesCharge.value = (hours * 60) * hourlyRate;
}
}
if (selectedOrder.value.startKitoMetersReading != null && selectedOrder.value.endKitoMetersReading != null) {
double startKm = double.tryParse(selectedOrder.value.startKitoMetersReading?.toString() ?? "0") ?? 0.0;
double endKm = double.tryParse(selectedOrder.value.endKitoMetersReading?.toString() ?? "0") ?? 0.0;
if (endKm > startKm) {
double totalKm = endKm - startKm;
if (totalKm > double.parse(selectedOrder.value.rentalPackageModel!.includedDistance!)) {
totalKm = totalKm - double.parse(selectedOrder.value.rentalPackageModel!.includedDistance!);
double extraKmRate = double.tryParse(selectedOrder.value.rentalPackageModel?.extraKmFare?.toString() ?? "0") ?? 0.0;
extraKilometerCharge.value = totalKm * extraKmRate;
}
}
}
subTotal.value = subTotal.value + extraKilometerCharge.value + extraMinutesCharge.value;
if (selectedOrder.value.taxSetting != null) {
for (var element in selectedOrder.value.taxSetting!) {
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
}
}
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
} catch (e) {
ShowToastDialog.showToast("Failed to calculate total: $e");
}
}
Future<void> completeOrder() async {
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
await FireStoreUtils.rentalOrderPlace(selectedOrder.value).then((value) {
ShowToastDialog.showToast("Payment method changed".tr);
Get.back();
Get.back();
});
} else {
selectedOrder.value.paymentStatus = true;
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: selectedOrder.value.id,
note: "Rental Amount debited".tr,
paymentStatus: "success".tr,
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
}
});
}
await FireStoreUtils.rentalOrderPlace(selectedOrder.value).then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
Get.back();
Get.back();
});
}
}
/// Return filtered list for a specific tab title
List<RentalOrderModel> getOrdersForTab(String tab) {
switch (tab) {
case "New":
return rentalOrders.where((order) => ["Order Placed", "Order Accepted", "Driver Pending"].contains(order.status)).toList();
case "On Going":
return rentalOrders.where((order) => ["Driver Accepted", "Order Shipped", "In Transit"].contains(order.status)).toList();
case "Completed":
return rentalOrders.where((order) => ["Order Completed"].contains(order.status)).toList();
case "Cancelled":
return rentalOrders.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
default:
return [];
}
}
/// Old helper (optional)
List<RentalOrderModel> get filteredRentalOrders => getOrdersForTab(selectedTab.value);
Future<void> cancelRentalRequest(RentalOrderModel order, {List<TaxModel>? taxList}) async {
try {
isLoading.value = true;
order.status = Constant.orderCancelled;
await FireStoreUtils.rentalOrderPlace(order);
listenRentalOrders();
if (order.paymentMethod?.toLowerCase() != "cod") {
double totalTax = 0.0;
if (taxList != null) {
for (var element in taxList) {
totalTax += Constant.calculateTax(
amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(),
taxModel: element,
);
}
}
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
double refundAmount = subTotal + totalTax;
WalletTransactionModel walletTransaction = WalletTransactionModel(
id: Constant.getUuid(),
amount: refundAmount,
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: true,
// refund
orderId: order.id,
note: "Refund for cancelled booking".tr,
paymentStatus: "success".tr,
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(walletTransaction);
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
}
ShowToastDialog.showToast("Booking cancelled successfully".tr);
} catch (e) {
ShowToastDialog.showToast("Failed to cancel booking: $e".tr);
} finally {
isLoading.value = false;
}
}
@override
void onClose() {
_rentalSubscription?.cancel();
super.onClose();
}
}

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/on_boarding_model.dart';
import '../service/fire_store_utils.dart';
class OnboardingController extends GetxController {
RxInt currentPage = 0.obs;
late PageController pageController;
RxBool isLoading = true.obs;
RxList<OnBoardingModel> onboardingList = <OnBoardingModel>[].obs;
@override
void onInit() {
super.onInit();
pageController = PageController();
getOnBoardingData();
}
void nextPage() {
if (currentPage.value < onboardingList.length - 1) {
pageController.nextPage(duration: 300.milliseconds, curve: Curves.ease);
}
}
void onPageChanged(int index) {
currentPage.value = index;
}
Future<void> getOnBoardingData() async {
isLoading.value = true;
await FireStoreUtils.getOnBoardingList().then((value) {
onboardingList.value = value;
});
isLoading.value = false;
}
@override
void onClose() {
pageController.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,214 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../models/onprovider_order_model.dart';
import '../models/provider_serivce_model.dart';
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
import '../screen_ui/on_demand_service/on_demand_payment_screen.dart';
import '../service/fire_store_utils.dart';
import '../service/send_notification.dart';
import '../themes/show_toast_dialog.dart';
import 'on_demand_dashboard_controller.dart';
class OnDemandBookingController extends GetxController {
Rxn<ProviderServiceModel> provider = Rxn<ProviderServiceModel>();
RxString categoryTitle = ''.obs;
RxInt quantity = 1.obs;
Rx<TextEditingController> descriptionController = TextEditingController().obs;
Rx<TextEditingController> dateTimeController = TextEditingController().obs;
Rx<TextEditingController> couponTextController = TextEditingController().obs;
Rx<DateTime> selectedDateTime = DateTime.now().obs;
RxString dateTimeText = "".obs;
RxList<CouponModel> couponList = <CouponModel>[].obs;
RxDouble subTotal = 0.0.obs;
RxDouble price = 0.0.obs;
RxDouble discountAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
RxString discountType = "".obs;
RxString discountLabel = "".obs;
RxString offerCode = "".obs;
Rx<ShippingAddress> selectedAddress = ShippingAddress().obs;
@override
void onInit() {
super.onInit();
final Map<String, dynamic>? args = Get.arguments;
if (args != null) {
provider.value = args['providerModel'];
categoryTitle.value = args['categoryTitle'] ?? '';
}
selectedAddress.value = Constant.selectedLocation;
fetchCoupons();
calculatePrice();
}
void fetchCoupons() {
if (provider.value?.author != null && provider.value!.author!.isNotEmpty) {
FireStoreUtils.getProviderCoupon(provider.value!.author!).then((activeCoupons) => couponList.assignAll(activeCoupons));
FireStoreUtils.getProviderCouponAfterExpire(provider.value!.author!).then((expiredCoupons) => couponList.addAll(expiredCoupons));
}
}
void incrementQuantity() {
quantity.value++;
calculatePrice();
}
void decrementQuantity() {
if (quantity.value > 1) {
quantity.value--;
calculatePrice();
}
}
void setDateTime(DateTime dateTime) {
selectedDateTime.value = dateTime;
dateTimeText.value = DateFormat('dd-MM-yyyy HH:mm').format(dateTime);
dateTimeController.value.text = dateTimeText.value;
}
void applyCoupon(CouponModel coupon) {
double discount = 0.0;
if (coupon.discountType == "Percentage" || coupon.discountType == "Percent") {
discount = price.value * (double.tryParse(coupon.discount.toString()) ?? 0) / 100;
} else {
discount = double.tryParse(coupon.discount.toString()) ?? 0;
}
if (subTotal.value > discount) {
discountType.value = coupon.discountType ?? '';
discountLabel.value = coupon.discount.toString();
offerCode.value = coupon.code ?? '';
calculatePrice();
} else {
Get.snackbar("Error", "Coupon cannot be applied");
}
}
String getDate(String date) {
try {
DateTime dt = DateTime.parse(date);
return "${dt.day}-${dt.month}-${dt.year}";
} catch (e) {
return date;
}
}
void calculatePrice() {
double basePrice =
(provider.value?.disPrice == "" || provider.value?.disPrice == "0")
? double.tryParse(provider.value?.price.toString() ?? "0") ?? 0
: double.tryParse(provider.value?.disPrice.toString() ?? "0") ?? 0;
price.value = basePrice * quantity.value;
// discount
if (discountType.value == "Percentage" || discountType.value == "Percent") {
discountAmount.value = price.value * (double.tryParse(discountLabel.value) ?? 0) / 100;
} else {
discountAmount.value = double.tryParse(discountLabel.value.isEmpty ? '0' : discountLabel.value) ?? 0;
}
subTotal.value = price.value - discountAmount.value;
// tax calculation
double total = subTotal.value;
for (var element in Constant.taxList) {
total += Constant.getTaxValue(amount: subTotal.value.toString(), taxModel: element);
}
totalAmount.value = total;
}
Future<void> confirmBooking(BuildContext context) async {
if (selectedAddress.value.getFullAddress().isEmpty) {
ShowToastDialog.showToast("Please enter address".tr);
} else if (dateTimeController.value.text.isEmpty) {
ShowToastDialog.showToast("Please select time slot.".tr);
} else {
UserModel? providerUser = await FireStoreUtils.getUserProfile(provider.value!.author!);
if (provider.value?.priceUnit == "Fixed") {
OnProviderOrderModel onDemandOrderModel = OnProviderOrderModel(
authorID: FireStoreUtils.getCurrentUid(),
author: Constant.userModel!,
quantity: double.parse(quantity.value.toString()),
sectionId: Constant.sectionConstantModel!.id,
address: selectedAddress.value,
taxModel: Constant.taxList,
provider: provider.value,
status: Constant.orderPlaced,
scheduleDateTime: Timestamp.fromDate(selectedDateTime.value),
notes: descriptionController.value.text,
discount: discountAmount.toString(),
discountType: discountType.toString(),
discountLabel: discountLabel.toString(),
adminCommission:
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
? '0'
: "${providerUser?.adminCommissionModel?.amount ?? Constant.sectionConstantModel?.adminCommision?.amount ?? 0}",
adminCommissionType:
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
? 'fixed'
: providerUser?.adminCommissionModel?.commissionType ?? Constant.sectionConstantModel?.adminCommision?.commissionType,
otp: Constant.getReferralCode(),
couponCode: offerCode.toString(),
);
print('totalAmount ::::::: ${double.tryParse(Constant.amountShow(amount: totalAmount.value.toString())) ?? 0.0}');
print('totalAmount value ::::::: ${totalAmount.value}');
Get.to(() => OnDemandPaymentScreen(), arguments: {'onDemandOrderModel': Rxn<OnProviderOrderModel>(onDemandOrderModel), 'totalAmount': totalAmount.value, 'isExtra': false});
} else {
ShowToastDialog.showLoader("Please wait...".tr);
OnProviderOrderModel onDemandOrder = OnProviderOrderModel(
otp: Constant.getReferralCode(),
authorID: FireStoreUtils.getCurrentUid(),
author: Constant.userModel!,
sectionId: Constant.sectionConstantModel!.id,
address: selectedAddress.value,
taxModel: Constant.taxList,
status: Constant.orderPlaced,
createdAt: Timestamp.now(),
quantity: double.parse(quantity.value.toString()),
provider: provider.value,
extraPaymentStatus: true,
scheduleDateTime: Timestamp.fromDate(selectedDateTime.value),
notes: descriptionController.value.text,
adminCommission:
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
? '0'
: "${providerUser?.adminCommissionModel?.amount ?? Constant.sectionConstantModel?.adminCommision?.amount ?? 0}",
adminCommissionType:
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
? 'fixed'
: providerUser?.adminCommissionModel?.commissionType ?? Constant.sectionConstantModel?.adminCommision?.commissionType,
paymentStatus: true,
);
await FireStoreUtils.onDemandOrderPlace(onDemandOrder, 0.0);
await FireStoreUtils.sendOrderOnDemandServiceEmail(orderModel: onDemandOrder);
if (providerUser != null) {
Map<String, dynamic> payLoad = {"type": 'provider_order', "orderId": onDemandOrder.id};
await SendNotification.sendFcmMessage(Constant.bookingPlaced, providerUser.fcmToken.toString(), payLoad);
}
ShowToastDialog.closeLoader();
Get.offAll(const OnDemandDashboardScreen());
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
controller.selectedIndex.value = 2;
ShowToastDialog.showToast("OnDemand Service successfully booked".tr);
}
}
}
}

View File

@@ -0,0 +1,29 @@
import 'package:get/get.dart';
import '../models/category_model.dart';
import '../service/fire_store_utils.dart';
class OnDemandCategoryController extends GetxController {
RxBool isLoading = true.obs;
RxList<CategoryModel> categories = <CategoryModel>[].obs;
@override
void onInit() {
super.onInit();
fetchCategories();
}
void fetchCategories() async {
try {
isLoading.value = true;
// Fetch categories
FireStoreUtils.getOnDemandCategory().then((catValue) {
categories.value = catValue;
});
} catch (e) {
print("Error fetching categories: $e");
} finally {
isLoading.value = false;
}
}
}

View File

@@ -0,0 +1,40 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/screen_ui/on_demand_service/favourite_ondemand_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
import '../screen_ui/on_demand_service/my_booking_on_demand_screen.dart';
import '../screen_ui/on_demand_service/on_demand_home_screen.dart';
class OnDemandDashboardController extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
getTaxList();
if (Constant.walletSetting == false) {
pageList.value = [OnDemandHomeScreen(), FavouriteOndemandScreen(), const MyBookingOnDemandScreen(), const ProfileScreen()];
} else {
pageList.value = [
OnDemandHomeScreen(),
FavouriteOndemandScreen(),
const MyBookingOnDemandScreen(),
const WalletScreen(),
const ProfileScreen(),
];
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
}

View File

@@ -0,0 +1,100 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/user_model.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../models/favorite_ondemand_service_model.dart';
import '../models/provider_serivce_model.dart';
import '../models/rating_model.dart';
import '../service/fire_store_utils.dart';
class OnDemandDetailsController extends GetxController {
late ProviderServiceModel provider;
final Rxn<UserModel> userModel = Rxn<UserModel>();
final RxString subCategoryTitle = ''.obs;
final RxString categoryTitle = ''.obs;
final RxList<RatingModel> ratingService = <RatingModel>[].obs;
final RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
final RxBool isLoading = true.obs;
final RxBool isOpen = false.obs;
final RxString tabString = "About".obs;
@override
void onInit() {
super.onInit();
provider = Get.arguments['providerModel'];
timeCheck();
getData();
}
Future<void> getData() async {
await getReviewList();
await getAuthor(); //fetch and set provider author here
if (Constant.userModel != null) {
lstFav.value = await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid());
}
isLoading.value = false;
}
Future<void> getReviewList() async {
await FireStoreUtils.getCategoryById(provider.categoryId.toString()).then((value) {
if (value != null) {
categoryTitle.value = value.title.toString();
}
});
await FireStoreUtils.getSubCategoryById(provider.subCategoryId.toString()).then((value) {
if (value != null) {
subCategoryTitle.value = value.title.toString();
}
});
await FireStoreUtils.getReviewByProviderServiceId(provider.id.toString()).then((value) {
ratingService.value = value;
});
if (Constant.userModel != null) {
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((value) {
lstFav.value = value;
});
}
}
Future<void> getAuthor() async {
final authorId = provider.author?.toString();
if (authorId != null && authorId.isNotEmpty) {
final user = await FireStoreUtils.getUserProfile(authorId);
if (user != null) {
userModel.value = user;
}
}
}
void timeCheck() {
final now = DateTime.now();
final day = DateFormat('EEEE', 'en_US').format(now);
final date = DateFormat('dd-MM-yyyy').format(now);
for (var element in provider.days) {
if (day == element.toString()) {
final start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${provider.startTime}");
final end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${provider.endTime}");
if (isCurrentDateInRange(start, end)) {
isOpen.value = true;
}
}
}
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
void changeTab(String tab) {
tabString.value = tab;
}
}

View File

@@ -0,0 +1,142 @@
import 'package:customer/models/banner_model.dart';
import 'package:customer/models/category_model.dart';
import 'package:customer/models/favorite_ondemand_service_model.dart';
import 'package:customer/models/provider_serivce_model.dart';
import 'package:customer/screen_ui/auth_screens/login_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../constant/constant.dart';
class OnDemandHomeController extends GetxController {
RxBool isLoading = true.obs;
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
RxList<CategoryModel> categories = <CategoryModel>[].obs;
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
/// Store last fetched category
Rx<CategoryModel?> categoryModel = Rx<CategoryModel?>(null);
@override
void onInit() {
getData();
super.onInit();
}
Future<void> getData() async {
isLoading.value = true;
await getZone();
// Fetch banners
FireStoreUtils.getHomeTopBanner().then((value) {
bannerTopHome.value = value;
});
// Fetch categories
FireStoreUtils.getOnDemandCategory().then((catValue) {
categories.value = catValue;
});
// Fetch provider services
FireStoreUtils.getProviderFuture()
.then((providerServiceList) {
Set<String?> uniqueAuthorIds = providerServiceList.map((service) => service.author).toSet();
List<String?> listOfUniqueProviders = uniqueAuthorIds.toList();
List<ProviderServiceModel> filteredProviders = [];
for (var provider in listOfUniqueProviders) {
List<ProviderServiceModel> filteredList = providerServiceList.where((service) => service.author == provider).toList();
filteredList.sort((a, b) => a.createdAt!.compareTo(b.createdAt!));
for (int index = 0; index < filteredList.length; index++) {
final service = filteredList[index];
if (Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel?.adminCommision?.isEnabled == true) {
if (service.subscriptionPlan?.itemLimit == "-1") {
filteredProviders.add(service);
} else {
if (index < int.parse(service.subscriptionPlan?.itemLimit ?? '0')) {
filteredProviders.add(service);
}
}
} else {
filteredProviders.add(service);
}
}
}
providerList.value = filteredProviders;
isLoading.value = false;
})
.catchError((e) {
print("Provider error: $e");
isLoading.value = false;
});
FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((favList) {
lstFav.value = favList;
});
}
/// Get category by id safely from cached categories
Future<CategoryModel?> getCategory(String? categoryId) async {
if (categoryId == null || categoryId.isEmpty) return null;
// Try to find category from cached list
CategoryModel? cat = categories.firstWhereOrNull((element) => element.id == categoryId);
// If not found, fetch from Firestore
cat ??= await FireStoreUtils.getCategoryById(categoryId);
categoryModel.value = cat;
return cat;
}
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
void toggleFavourite(ProviderServiceModel provider) {
if (Constant.userModel == null) {
Get.to(LoginScreen());
} else {
var contain = lstFav.where((element) => element.service_id == provider.id);
if (contain.isNotEmpty) {
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
section_id: provider.sectionId,
service_id: provider.id,
user_id: FireStoreUtils.getCurrentUid(),
serviceAuthorId: provider.author,
);
FireStoreUtils.removeFavouriteOndemandService(favouriteModel);
lstFav.removeWhere((item) => item.service_id == provider.id);
} else {
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
section_id: provider.sectionId,
service_id: provider.id,
user_id: FireStoreUtils.getCurrentUid(),
serviceAuthorId: provider.author,
);
FireStoreUtils.setFavouriteOndemandSection(favouriteModel);
lstFav.add(favouriteModel);
}
}
}
Future<void> getZone() async {
await FireStoreUtils.getZone().then((value) {
if (value != null) {
for (int i = 0; i < value.length; i++) {
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location?.latitude ?? 0.0, Constant.selectedLocation.location?.longitude ?? 0.0), value[i].area!)) {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = true;
break;
} else {
Constant.selectedZone = value[i];
Constant.isZoneAvailable = false;
}
}
}
});
}
}

View File

@@ -0,0 +1,254 @@
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import '../constant/constant.dart';
import '../models/onprovider_order_model.dart';
import '../models/wallet_transaction_model.dart';
import '../models/worker_model.dart';
import '../service/fire_store_utils.dart';
import '../service/send_notification.dart';
import '../themes/show_toast_dialog.dart';
class OnDemandOrderDetailsController extends GetxController {
Rx<UserModel?> providerUser = Rx<UserModel?>(null);
Rxn<OnProviderOrderModel> onProviderOrder = Rxn<OnProviderOrderModel>();
Rxn<WorkerModel> worker = Rxn<WorkerModel>();
Rx<TextEditingController> couponTextController = TextEditingController().obs;
Rx<TextEditingController> cancelBookingController = TextEditingController().obs;
RxDouble subTotal = 0.0.obs;
RxDouble price = 0.0.obs;
RxDouble discountAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
RxDouble quantity = 0.0.obs;
RxString discountType = "".obs;
RxString discountLabel = "".obs;
RxString offerCode = "".obs;
RxList<CouponModel> couponList = <CouponModel>[].obs;
final RxBool isLoading = false.obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args is OnProviderOrderModel) {
onProviderOrder.value = args;
}
getData();
}
Future<void> getData() async {
try {
final order = await FireStoreUtils.getProviderOrderById(onProviderOrder.value!.id);
if (order != null) {
onProviderOrder.value = order;
discountType.value = order.discountType ?? "";
discountLabel.value = order.discountLabel ?? "";
discountAmount.value = double.tryParse(order.discount.toString()) ?? 0.0;
offerCode.value = order.couponCode ?? "";
// Fetch provider
providerUser.value = await FireStoreUtils.getUserProfile(order.provider.author.toString());
// Fetch worker (if exists)
if (order.workerId != null && order.workerId!.isNotEmpty) {
worker.value = await FireStoreUtils.getWorker(order.workerId!);
} else {
worker.value = null;
}
calculatePrice();
// Load available coupons
FireStoreUtils.getProviderCouponAfterExpire(order.provider.author.toString()).then((expiredCoupons) {
couponList.assignAll(expiredCoupons);
});
} else {
onProviderOrder.value = null;
providerUser.value = null;
worker.value = null;
couponList.clear();
}
} catch (e, st) {
log("Error in getData: $e\n$st");
onProviderOrder.value = null;
providerUser.value = null;
worker.value = null;
couponList.clear();
}
}
void applyCoupon(CouponModel coupon) {
double discount = 0.0;
if (coupon.discountType == "Percentage" || coupon.discountType == "Percent") {
discount = price.value * (double.tryParse(coupon.discount.toString()) ?? 0) / 100;
} else {
discount = double.tryParse(coupon.discount.toString()) ?? 0;
}
if (subTotal.value > discount) {
discountType.value = coupon.discountType ?? '';
discountLabel.value = coupon.discount.toString();
offerCode.value = coupon.code ?? '';
calculatePrice();
} else {
Get.snackbar("Error", "Coupon cannot be applied");
}
}
void calculatePrice() {
double basePrice =
(onProviderOrder.value?.provider.disPrice == "" || onProviderOrder.value?.provider.disPrice == "0")
? double.tryParse(onProviderOrder.value?.provider.price.toString() ?? "0") ?? 0
: double.tryParse(onProviderOrder.value?.provider.disPrice.toString() ?? "0") ?? 0;
price.value = basePrice * (onProviderOrder.value?.quantity ?? 0.0);
// discount
if (discountType.value == "Percentage" || discountType.value == "Percent") {
discountAmount.value = price.value * (double.tryParse(discountLabel.value) ?? 0) / 100;
} else {
discountAmount.value = double.tryParse(discountLabel.value.isEmpty ? '0' : discountLabel.value) ?? 0;
}
subTotal.value = price.value - discountAmount.value;
// tax calculation
double total = subTotal.value;
for (var element in Constant.taxList) {
total += Constant.getTaxValue(amount: subTotal.value.toString(), taxModel: element);
}
totalAmount.value = total;
}
String getDate(String date) {
try {
DateTime dt = DateTime.parse(date);
return "${dt.day}-${dt.month}-${dt.year}";
} catch (e) {
return date;
}
}
Future<void> cancelBooking() async {
final order = onProviderOrder.value;
if (order == null) return;
ShowToastDialog.showLoader("Please wait...".tr);
try {
double total = 0.0;
// Calculate total
final pricePerUnit =
(order.provider.disPrice == "" || order.provider.disPrice == "0") ? double.tryParse(order.provider.price.toString()) ?? 0 : double.tryParse(order.provider.disPrice.toString()) ?? 0;
total = pricePerUnit * (order.quantity);
// Add tax
if (Constant.taxList.isNotEmpty) {
for (var tax in Constant.taxList) {
total += Constant.getTaxValue(amount: total.toString(), taxModel: tax);
}
}
// Admin commission
double adminComm = 0.0;
if ((order.adminCommission ?? '0') != '0' && (order.adminCommissionType ?? '').isNotEmpty) {
if (order.adminCommissionType!.toLowerCase() == 'percentage' || order.adminCommissionType!.toLowerCase() == 'percent') {
adminComm = (total * (double.tryParse(order.adminCommission!) ?? 0)) / 100;
} else {
adminComm = double.tryParse(order.adminCommission!) ?? 0;
}
}
// Refund customer wallet if not COD
if ((order.payment_method).toLowerCase() != 'cod') {
await FireStoreUtils.setWalletTransaction(
WalletTransactionModel(
id: Constant.getUuid(),
serviceType: 'ondemand-service',
amount: total,
date: Timestamp.now(),
paymentMethod: 'wallet',
transactionUser: 'customer',
userId: Constant.userModel?.id,
isTopup: true,
orderId: order.id,
note: 'Booking Amount Refund',
paymentStatus: "success".tr,
),
);
// Deduct from provider if accepted
if (order.status == Constant.orderAccepted) {
await FireStoreUtils.setWalletTransaction(
WalletTransactionModel(
id: Constant.getUuid(),
serviceType: 'ondemand-service',
amount: total,
date: Timestamp.now(),
paymentMethod: 'wallet',
transactionUser: 'provider',
userId: order.provider.author ?? '',
isTopup: false,
orderId: order.id,
note: 'Booking Amount Refund',
paymentStatus: "success".tr,
),
);
}
}
// Refund admin commission
if (order.status == Constant.orderAccepted && adminComm > 0) {
await FireStoreUtils.setWalletTransaction(
WalletTransactionModel(
id: Constant.getUuid(),
serviceType: 'ondemand-service',
amount: adminComm,
date: Timestamp.now(),
paymentMethod: 'wallet',
transactionUser: 'provider',
userId: order.provider.author ?? '',
isTopup: true,
orderId: order.id,
note: 'Admin commission refund',
paymentStatus: "success".tr,
),
);
}
// Update order status & reason
order.status = Constant.orderCancelled;
order.reason = cancelBookingController.value.text;
await FireStoreUtils.updateOnDemandOrder(order); // Ensure this completes
// Notify provider
final provider = await FireStoreUtils.getUserProfile(order.provider.author ?? '');
if (provider != null) {
Map<String, dynamic> payload = {"type": 'provider_order', "orderId": order.id};
await SendNotification.sendFcmMessage(Constant.bookingPlaced, provider.fcmToken ?? '', payload);
}
ShowToastDialog.closeLoader();
Get.back();
ShowToastDialog.showToast("Booking cancelled successfully".tr);
} catch (e, st) {
log("Cancel error: $e\n$st");
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Something went wrong".tr);
}
}
}

View File

@@ -0,0 +1,169 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/collection_name.dart';
import '../models/onprovider_order_model.dart';
import '../models/provider_serivce_model.dart';
import '../models/rating_model.dart';
import '../models/worker_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
import '../constant/constant.dart';
import '../themes/show_toast_dialog.dart';
class OnDemandReviewController extends GetxController {
final Rxn<OnProviderOrderModel> order = Rxn<OnProviderOrderModel>();
final RxString reviewFor = "".obs;
final Rxn<RatingModel> ratingModel = Rxn<RatingModel>();
final RxDouble ratings = 0.0.obs;
final TextEditingController comment = TextEditingController();
final Rxn<UserModel> provider = Rxn<UserModel>();
final Rxn<ProviderServiceModel> providerServiceModel = Rxn<ProviderServiceModel>();
final Rxn<WorkerModel> workerModel = Rxn<WorkerModel>();
final RxInt providerReviewCount = 0.obs;
final RxDouble providerReviewSum = 0.0.obs;
final RxInt serviceReviewCount = 0.obs;
final RxDouble serviceReviewSum = 0.0.obs;
final RxInt workerReviewCount = 0.obs;
final RxDouble workerReviewSum = 0.0.obs;
final FirebaseFirestore firestore = FirebaseFirestore.instance;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null) {
order.value = args['order'];
reviewFor.value = args['reviewFor'];
getReview();
}
}
void getReview() async {
// Get existing rating
if (reviewFor.value == "Provider") {
RatingModel? value = await FireStoreUtils.getReviewsByProviderID(order.value!.id, order.value!.provider.author.toString());
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0.0;
comment.text = value.comment ?? '';
}
} else {
RatingModel? value = await FireStoreUtils.getReviewsByWorkerID(order.value!.id, order.value!.workerId.toString());
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0.0;
comment.text = value.comment ?? '';
}
}
// Worker review logic
if (reviewFor.value == "Worker") {
WorkerModel? value = await FireStoreUtils.getWorker(order.value!.workerId.toString());
if (value != null) {
workerModel.value = value;
final int existingCount = (value.reviewsCount ?? 0).toInt();
final double existingSum = (value.reviewsSum ?? 0.0).toDouble();
final double oldRating = ratingModel.value?.rating ?? 0.0;
workerReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
workerReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
}
}
// Provider & service review logic
else {
UserModel? user = await FireStoreUtils.getUserProfile(order.value!.provider.author.toString());
if (user != null) {
provider.value = user;
final int existingCount = int.tryParse(user.reviewsCount?.toString() ?? '0') ?? 0;
final double existingSum = double.tryParse(user.reviewsSum?.toString() ?? '0.0') ?? 0.0;
final double oldRating = ratingModel.value?.rating ?? 0.0;
providerReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
providerReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
}
ProviderServiceModel? service = await FireStoreUtils.getCurrentProvider(order.value!.provider.id.toString());
if (service != null) {
providerServiceModel.value = service;
final int existingCount = (service.reviewsCount ?? 0).toInt();
final double existingSum = (service.reviewsSum ?? 0.0).toDouble();
final double oldRating = ratingModel.value?.rating ?? 0.0;
serviceReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
serviceReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
}
}
}
void submitReview() async {
if (reviewFor.value == "Provider") {
await _providerReviewSubmit();
} else {
await _workerReviewSubmit();
}
}
Future<void> _providerReviewSubmit() async {
ShowToastDialog.showLoader("Submit in...".tr);
providerServiceModel.value!.reviewsCount = serviceReviewCount.value + 1;
providerServiceModel.value!.reviewsSum = serviceReviewSum.value + ratings.value;
// Convert to string only if your model field is String
provider.value!.reviewsCount = (providerReviewCount.value + 1).toString();
provider.value!.reviewsSum = (providerReviewSum.value + ratings.value).toString();
RatingModel rate = RatingModel(
id: ratingModel.value?.id ?? firestore.collection(CollectionName.itemsReview).doc().id,
productId: ratingModel.value?.productId ?? order.value!.provider.id,
comment: comment.text,
photos: ratingModel.value?.photos ?? [],
rating: ratings.value,
orderId: ratingModel.value?.orderId ?? order.value!.id,
vendorId: ratingModel.value?.vendorId ?? order.value!.provider.author.toString(),
customerId: Constant.userModel?.id,
uname: '${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}',
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(rate);
await FireStoreUtils.updateUser(provider.value!);
await FireStoreUtils.updateProvider(providerServiceModel.value!);
ShowToastDialog.closeLoader();
Get.back(result: true);
}
Future<void> _workerReviewSubmit() async {
ShowToastDialog.showLoader("Submit in...".tr);
workerModel.value!.reviewsCount = workerReviewCount.value + 1;
workerModel.value!.reviewsSum = workerReviewSum.value + ratings.value;
RatingModel rate = RatingModel(
id: ratingModel.value?.id ?? firestore.collection(CollectionName.itemsReview).doc().id,
productId: ratingModel.value?.productId ?? order.value!.provider.id,
comment: comment.text,
photos: ratingModel.value?.photos ?? [],
rating: ratings.value,
orderId: ratingModel.value?.orderId ?? order.value!.id,
driverId: ratingModel.value?.driverId ?? order.value!.workerId.toString(),
customerId: Constant.userModel?.id,
uname: '${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}',
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(rate);
await FireStoreUtils.updateWorker(workerModel.value!);
ShowToastDialog.closeLoader();
Get.back(result: true);
}
}

View File

@@ -0,0 +1,51 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/cart_product_model.dart';
import 'package:customer/models/order_model.dart';
import '../service/cart_provider.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class OrderController extends GetxController {
RxList<OrderModel> allList = <OrderModel>[].obs;
RxList<OrderModel> inProgressList = <OrderModel>[].obs;
RxList<OrderModel> deliveredList = <OrderModel>[].obs;
RxList<OrderModel> rejectedList = <OrderModel>[].obs;
RxList<OrderModel> cancelledList = <OrderModel>[].obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getOrder();
super.onInit();
}
Future<void> getOrder() async {
if (Constant.userModel != null) {
await FireStoreUtils.getAllOrder().then((value) {
allList.value = value;
rejectedList.value = allList.where((p0) => p0.status == Constant.orderRejected).toList();
inProgressList.value =
allList
.where(
(p0) => p0.status == Constant.orderAccepted || p0.status == Constant.driverPending || p0.status == Constant.orderShipped || p0.status == Constant.orderInTransit,
)
.toList();
deliveredList.value = allList.where((p0) => p0.status == Constant.orderCompleted).toList();
cancelledList.value = allList.where((p0) => p0.status == Constant.orderCancelled).toList();
});
}
isLoading.value = false;
}
final CartProvider cartProvider = CartProvider();
void addToCart({required CartProductModel cartProductModel}) {
cartProvider.addToCart(Get.context!, cartProductModel, cartProductModel.quantity!);
update();
}
}

View File

@@ -0,0 +1,77 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/cart_product_model.dart';
import 'package:customer/models/order_model.dart';
import 'package:get/get.dart';
import '../service/cart_provider.dart';
class OrderDetailsController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Rx<OrderModel> orderModel = OrderModel().obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
orderModel.value = argumentData['orderModel'];
}
calculatePrice();
update();
}
RxDouble subTotal = 0.0.obs;
RxDouble specialDiscountAmount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
Future<void> calculatePrice() async {
subTotal.value = 0.0;
specialDiscountAmount.value = 0.0;
taxAmount.value = 0.0;
totalAmount.value = 0.0;
for (var element in orderModel.value.products!) {
if (double.parse(element.discountPrice.toString()) <= 0) {
subTotal.value = subTotal.value +
double.parse(element.price.toString()) * double.parse(element.quantity.toString()) +
(double.parse(element.extrasPrice.toString()) * double.parse(element.quantity.toString()));
} else {
subTotal.value = subTotal.value +
double.parse(element.discountPrice.toString()) * double.parse(element.quantity.toString()) +
(double.parse(element.extrasPrice.toString()) * double.parse(element.quantity.toString()));
}
}
if (orderModel.value.specialDiscount != null && orderModel.value.specialDiscount!['special_discount'] != null) {
specialDiscountAmount.value = double.parse(orderModel.value.specialDiscount!['special_discount'].toString());
}
if (orderModel.value.taxSetting != null) {
for (var element in orderModel.value.taxSetting!) {
taxAmount.value = taxAmount.value +
Constant.calculateTax(amount: (subTotal.value - double.parse(orderModel.value.discount.toString()) - specialDiscountAmount.value).toString(), taxModel: element);
}
}
totalAmount.value = (subTotal.value - double.parse(orderModel.value.discount.toString()) - specialDiscountAmount.value) +
taxAmount.value +
double.parse(orderModel.value.deliveryCharge.toString()) +
double.parse(orderModel.value.tipAmount.toString());
isLoading.value = false;
}
final CartProvider cartProvider = CartProvider();
void addToCart({required CartProductModel cartProductModel}) {
cartProvider.addToCart(Get.context!, cartProductModel, cartProductModel.quantity!);
update();
}
}

View File

@@ -0,0 +1,43 @@
import 'dart:async';
import 'package:customer/models/order_model.dart';
import 'package:get/get.dart';
import '../service/database_helper.dart';
class OrderPlacingController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
startTimer();
super.onInit();
}
Rx<OrderModel> orderModel = OrderModel().obs;
Future<void> getArgument() async {
DatabaseHelper.instance.deleteAllCartProducts();
dynamic argumentData = Get.arguments;
if (argumentData != null) {
orderModel.value = argumentData['orderModel'];
}
isLoading.value = false;
update();
}
Timer? timer;
RxInt counter = 0.obs;
RxBool isPlacing = false.obs;
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (counter.value == 3) {
timer.cancel();
isPlacing.value = true;
}
counter++;
});
}
}

View File

@@ -0,0 +1,36 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class OsmSearchPlaceController extends GetxController {
Rx<TextEditingController> searchTxtController = TextEditingController().obs;
RxList<SearchInfo> suggestionsList = <SearchInfo>[].obs;
@override
void onInit() {
super.onInit();
searchTxtController.value.addListener(() {
_onChanged();
});
}
void _onChanged() {
fetchAddress(searchTxtController.value.text);
}
Future<void> fetchAddress(text) async {
log(":: fetchAddress :: $text");
try {
String locale = 'en';
SharedPreferences sp = await SharedPreferences.getInstance();
if (sp.getString("languageCode") != null || sp.getString("languageCode")?.isNotEmpty == true) {
locale = sp.getString("languageCode") ?? "en";
}
suggestionsList.value = await addressSuggestion(text, locale: locale);
} catch (e) {
log(e.toString());
}
}
}

View File

@@ -0,0 +1,131 @@
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/constant.dart';
import '../models/user_model.dart';
import '../screen_ui/auth_screens/login_screen.dart';
import '../screen_ui/auth_screens/sign_up_screen.dart';
import '../screen_ui/service_home_screen/service_list_screen.dart';
import '../service/fire_store_utils.dart';
import '../utils/notification_service.dart';
class OtpVerifyController extends GetxController {
/// Use a normal controller (NOT obs)
final Rx<TextEditingController> otpController = TextEditingController().obs;
/// Reactive Strings
final RxString countryCode = "".obs;
final RxString phoneNumber = "".obs;
final RxString verificationId = "".obs;
RxInt resendToken = 0.obs;
final FirebaseAuth _auth = FirebaseAuth.instance;
@override
void onInit() {
super.onInit();
final args = Get.arguments ?? {};
countryCode.value = args['countryCode'] ?? "";
phoneNumber.value = args['phoneNumber'] ?? "";
verificationId.value = args['verificationId'] ?? "";
}
Future<bool> sendOTP() async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: countryCode.value + phoneNumber.value,
verificationCompleted: (PhoneAuthCredential credential) {},
verificationFailed: (FirebaseAuthException e) {},
codeSent: (String verificationId0, int? resendToken0) async {
verificationId.value = verificationId0;
resendToken.value = resendToken0!;
ShowToastDialog.showToast("OTP sent".tr);
},
timeout: const Duration(seconds: 25),
forceResendingToken: resendToken.value,
codeAutoRetrievalTimeout: (String verificationId0) {
verificationId0 = verificationId.value;
},
);
return true;
}
void verifyOtp() async {
if (otpController.value.text.length != 6) {
ShowToastDialog.showToast("Enter valid 6-digit OTP".tr);
return;
}
try {
ShowToastDialog.showLoader("Verifying OTP...".tr);
final credential = PhoneAuthProvider.credential(verificationId: verificationId.value, smsCode: otpController.value.text.trim());
final fcmToken = await NotificationService.getToken();
final result = await _auth.signInWithCredential(credential);
if (result.additionalUserInfo?.isNewUser == true) {
final userModel = UserModel(id: result.user!.uid, countryCode: countryCode.value, phoneNumber: phoneNumber.value, fcmToken: fcmToken, active: true);
ShowToastDialog.closeLoader();
Get.to(() => const SignUpScreen(), arguments: {'type': 'mobileNumber', 'userModel': userModel});
return;
}
final exists = await FireStoreUtils.userExistOrNot(result.user!.uid);
ShowToastDialog.closeLoader();
if (!exists) {
final userModel = UserModel(id: result.user!.uid, countryCode: countryCode.value, phoneNumber: phoneNumber.value, fcmToken: fcmToken);
Get.off(() => const SignUpScreen(), arguments: {'type': 'mobileNumber', 'userModel': userModel});
return;
}
final userModel = await FireStoreUtils.getUserProfile(result.user!.uid);
if (userModel == null || userModel.role != 'customer') {
await _auth.signOut();
Get.offAll(() => const LoginScreen());
return;
}
if (userModel.active == false) {
ShowToastDialog.showToast("This user is disabled".tr);
await _auth.signOut();
Get.offAll(() => const LoginScreen());
return;
}
userModel.fcmToken = fcmToken;
await FireStoreUtils.updateUser(userModel);
if (userModel.shippingAddress?.isNotEmpty ?? false) {
final defaultAddress = userModel.shippingAddress!.firstWhere((e) => e.isDefault == true, orElse: () => userModel.shippingAddress!.first);
Constant.selectedLocation = defaultAddress;
Get.offAll(() => const ServiceListScreen());
} else {
Get.offAll(() => const LocationPermissionScreen());
}
} catch (e) {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Invalid OTP or Verification Failed".tr);
}
}
String maskPhoneNumber(String phone) {
if (phone.length < 4) return phone;
final first = phone.substring(0, 2);
final last = phone.substring(phone.length - 2);
return "$first*** ***$last";
}
@override
void dispose() {
otpController.value.dispose();
// TODO: implement dispose
super.dispose();
}
}

View File

@@ -0,0 +1,29 @@
import 'package:customer/models/coupon_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class ParcelCouponController extends GetxController{
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
void getData(){
getCouponCode();
}
RxBool isLoading = true.obs;
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
Future<void> getCouponCode() async {
await FireStoreUtils.getParcelCoupon().then((value) {
cabCouponList.value = value;
// Handle the retrieved coupon code
});
print("cabCouponList ${cabCouponList.length}");
isLoading.value = false;
}
}

View File

@@ -0,0 +1,35 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/screen_ui/parcel_service/home_parcel_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
import '../screen_ui/parcel_service/my_booking_screen.dart';
class ParcelDashboardController extends GetxController {
RxInt selectedIndex = 0.obs;
RxList pageList = [].obs;
@override
void onInit() {
getTaxList();
if (Constant.walletSetting == false) {
pageList.value = [const HomeParcelScreen(), const MyBookingScreen(), const ProfileScreen()];
} else {
pageList.value = [const HomeParcelScreen(), const MyBookingScreen(), const WalletScreen(), const ProfileScreen()];
}
super.onInit();
}
Future<void> getTaxList() async {
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
if (value != null) {
Constant.taxList = value;
}
});
}
DateTime? currentBackPressTime;
RxBool canPopNow = false.obs;
}

View File

@@ -0,0 +1,140 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../constant/constant.dart';
import '../models/parcel_order_model.dart';
import '../models/wallet_transaction_model.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
class ParcelMyBookingController extends GetxController {
RxBool isLoading = true.obs;
RxList<ParcelOrderModel> parcelOrder = <ParcelOrderModel>[].obs;
RxString selectedTab = "New".obs;
RxList<String> tabTitles = ["New", "In Transit", "Delivered", "Cancelled"].obs;
StreamSubscription<List<ParcelOrderModel>>? _parcelSubscription;
@override
void onInit() {
super.onInit();
listenParcelOrders();
}
void selectTab(String tab) {
selectedTab.value = tab;
}
/// Start listening to orders live. Cancel previous subscription first.
void listenParcelOrders() {
isLoading.value = true;
if (Constant.userModel == null) {
isLoading.value = false;
return;
}
_parcelSubscription?.cancel();
_parcelSubscription = FireStoreUtils.listenParcelOrders().listen(
(orders) {
parcelOrder.assignAll(orders);
isLoading.value = false;
},
onError: (err) {
isLoading.value = false;
// optionally handle error
},
);
}
/// Return filtered list for a specific tab title
List<ParcelOrderModel> getOrdersForTab(String tab) {
switch (tab) {
case "New":
return parcelOrder.where((order) => ["Order Placed"].contains(order.status)).toList();
case "In Transit":
return parcelOrder.where((order) => ["Order Accepted", "Driver Accepted", "Driver Pending", "Order Shipped", "In Transit"].contains(order.status)).toList();
case "Delivered":
return parcelOrder.where((order) => ["Order Completed"].contains(order.status)).toList();
case "Cancelled":
return parcelOrder.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
default:
return [];
}
}
/// Old helper (optional)
List<ParcelOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
Future<void> cancelParcelOrder(ParcelOrderModel order) async {
try {
isLoading.value = true;
if (order.status != Constant.orderPlaced) {
ShowToastDialog.showToast("You can only cancel before pickup.".tr);
return;
}
order.status = Constant.orderCancelled;
await FireStoreUtils.parcelOrderPlace(order);
listenParcelOrders();
if (order.paymentMethod?.toLowerCase() != "cod") {
double totalTax = 0.0;
final taxSettings = order.taxSetting ?? [];
for (var element in taxSettings) {
totalTax += Constant.calculateTax(amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(), taxModel: element);
}
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
double refundAmount = subTotal + totalTax;
WalletTransactionModel walletTransaction = WalletTransactionModel(
id: Constant.getUuid(),
amount: refundAmount,
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: true,
// refund
orderId: order.id,
note: "Refund for cancelled parcel order",
paymentStatus: "success",
serviceType: Constant.parcelServiceType,
);
// Save wallet transaction
await FireStoreUtils.setWalletTransaction(walletTransaction);
// Update wallet balance
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
}
ShowToastDialog.showToast("Order cancelled successfully".tr);
} catch (e) {
ShowToastDialog.showToast("${'Failed to cancel order:'.tr} $e".tr);
} finally {
isLoading.value = false;
}
}
@override
void onClose() {
_parcelSubscription?.cancel();
super.onClose();
}
}

View File

@@ -0,0 +1,983 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as maths;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:uuid/uuid.dart';
import '../../../models/parcel_order_model.dart';
import '../constant/constant.dart';
import '../models/payment_model/cod_setting_model.dart';
import '../models/payment_model/flutter_wave_model.dart';
import '../models/payment_model/mercado_pago_model.dart';
import '../models/payment_model/mid_trans.dart';
import '../models/payment_model/orange_money.dart';
import '../models/payment_model/pay_fast_model.dart';
import '../models/payment_model/pay_stack_model.dart';
import '../models/payment_model/paypal_model.dart';
import '../models/payment_model/paytm_model.dart';
import '../models/payment_model/razorpay_model.dart';
import '../models/payment_model/stripe_model.dart';
import '../models/payment_model/wallet_setting_model.dart';
import '../models/payment_model/xendit.dart';
import '../models/user_model.dart';
import '../payment/MercadoPagoScreen.dart';
import '../payment/PayFastScreen.dart';
import '../payment/getPaytmTxtToken.dart';
import '../payment/midtrans_screen.dart';
import '../payment/orangePayScreen.dart';
import '../payment/paystack/pay_stack_screen.dart';
import '../payment/paystack/pay_stack_url_model.dart';
import '../payment/paystack/paystack_url_genrater.dart';
import '../payment/stripe_failed_model.dart';
import '../payment/xenditModel.dart';
import '../payment/xenditScreen.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../screen_ui/parcel_service/order_successfully_placed.dart';
import '../service/fire_store_utils.dart';
import '../themes/app_them_data.dart';
import '../themes/show_toast_dialog.dart';
import '../utils/preferences.dart';
class ParcelOrderConfirmationController extends GetxController {
RxBool isLoading = true.obs;
final Rx<ParcelOrderModel> parcelOrder = ParcelOrderModel().obs;
final RxList<XFile> images = <XFile>[].obs;
final RxString paymentBy = "Receiver".obs;
RxString selectedPaymentMethod = ''.obs;
RxBool isOrderPlaced = false.obs;
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
Rx<TextEditingController> couponController = TextEditingController().obs;
Rx<UserModel> userModel = UserModel().obs;
@override
void onInit() {
super.onInit();
getArgument();
}
Rx<CouponModel> selectedCouponModel = CouponModel().obs;
Future<void> getArgument() async {
final dynamic args = Get.arguments;
if (args != null) {
parcelOrder.value = args['parcelOrder'];
images.value = List<XFile>.from(args['images'] ?? []);
calculatePrice();
}
userModel.value = Constant.userModel!;
await fetchCoupons();
await getPaymentSettings();
isLoading.value = false;
update();
}
void calculatePrice() {
subTotal.value = 0;
discount.value = 0;
taxAmount.value = 0;
subTotal.value = double.tryParse(parcelOrder.value.subTotal ?? '0') ?? 0.0;
if (selectedCouponModel.value.id != null) {
discount.value = Constant.calculateDiscount(amount: subTotal.value.toString(), offerModel: selectedCouponModel.value);
}
for (var element in Constant.taxList) {
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
}
print("Tax: ${taxAmount.value}");
print("Discount: ${discount.value}");
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
}
RxList<CouponModel> couponList = <CouponModel>[].obs;
Future<void> fetchCoupons() async {
try {
await FireStoreUtils.getParcelCoupon().then((value) {
couponList.value = value;
});
} catch (e) {
print("Error fetching coupons: $e");
}
}
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
Future<void> placeOrder() async {
ShowToastDialog.showLoader("Please wait...".tr);
try {
List<String> parcelImages = [];
if (images.isNotEmpty) {
for (var image in images) {
final upload = await FireStoreUtils.uploadChatImageToFireStorage(File(image.path), Get.context!);
parcelImages.add(upload.url);
}
}
parcelOrder.value.parcelImages = parcelImages;
parcelOrder.value.discount = discount.value.toString();
parcelOrder.value.discountType = selectedCouponModel.value.discountType.toString();
parcelOrder.value.discountLabel = selectedCouponModel.value.code.toString();
parcelOrder.value.adminCommission = Constant.sectionConstantModel?.adminCommision?.amount?.toString();
parcelOrder.value.adminCommissionType = Constant.sectionConstantModel?.adminCommision?.commissionType;
parcelOrder.value.status = Constant.orderPlaced;
parcelOrder.value.createdAt = Timestamp.now();
parcelOrder.value.author = userModel.value;
parcelOrder.value.authorID = FireStoreUtils.getCurrentUid();
parcelOrder.value.paymentMethod = paymentBy.value == "Receiver" ? "cod" : selectedPaymentMethod.value;
parcelOrder.value.paymentCollectByReceiver = paymentBy.value == "Receiver";
parcelOrder.value.senderZoneId = Constant.getZoneId(parcelOrder.value.senderLatLong!.latitude ?? 0.0, parcelOrder.value.senderLatLong!.longitude ?? 0.0);
parcelOrder.value.receiverZoneId = Constant.getZoneId(parcelOrder.value.receiverLatLong!.latitude ?? 0.0, parcelOrder.value.receiverLatLong!.longitude ?? 0.0);
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.value.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: parcelOrder.value.id,
note: "Parcel Amount debited",
paymentStatus: "success",
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
}
});
}
await FireStoreUtils.parcelOrderPlace(parcelOrder.value).then((value) async {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Order placed successfully".tr);
Get.offAll(() => OrderSuccessfullyPlaced(), arguments: {'parcelOrder': parcelOrder.value});
await FireStoreUtils.sendParcelBookEmail(orderModel: parcelOrder.value);
});
} catch (e) {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Something went wrong. Please try again.".tr);
}
}
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then((value) {
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.cod.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
} else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'eMart Customer';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
});
}
// Strip
Future<void> stripeMakePayment({required String amount}) async {
log(double.parse(amount).toStringAsFixed(0));
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
log("stripe Responce====>$paymentIntentData");
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
merchantDisplayName: 'GoRide',
),
);
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
log("$e \n$s");
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": Constant.userModel?.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
);
return jsonDecode(response.body);
} catch (e) {
log(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
},
],
"payer": {"email": Constant.userModel?.email},
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
"auto_return": "approved",
// Automatically return after payment is approved
});
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Error creating preference: ${response.body}');
return null;
}
}
//Paypal
void paypalPaymentSheet(String amount, BuildContext context) {
// ✅ Ensure amount format is correct (e.g. 10.00)
final formattedAmount = double.parse(amount).toStringAsFixed(2);
Navigator.of(context).push(
MaterialPageRoute(
builder:
(BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.emart.customer://paypalpay",
cancelURL: "com.emart.customer://paypalcancel",
transactions: [
{
"amount": {
"total": formattedAmount,
"currency": "USD",
"details": {"subtotal": formattedAmount},
},
},
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
debugPrint("✅ PayPal Payment Success: $params");
placeOrder();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
debugPrint("❌ PayPal Payment Error: $error");
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
debugPrint("⚠️ PayPal Payment Canceled: $params");
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
),
),
);
}
// void paypalPaymentSheet(String amount, context) {
// Navigator.of(context).push(
// MaterialPageRoute(
// builder:
// (BuildContext context) => UsePaypal(
// sandboxMode: payPalModel.value.isLive == true ? false : true,
// clientId: payPalModel.value.paypalClient ?? '',
// secretKey: payPalModel.value.paypalSecret ?? '',
// returnURL: "https://success.emart.com/return",
// cancelURL: "https://cancel.emart.com/cancel",
// // returnURL: "com.emart.customer://paypalpay",
// // cancelURL: "com.emart.customer://paypalpay",
// transactions: [
// {
// "amount": {
// "total": amount,
// "currency": "USD",
// "details": {"subtotal": amount},
// },
// },
// ],
// note: "Contact us for any questions on your order.",
// onSuccess: (Map params) async {
// placeOrder();
// ShowToastDialog.showToast("Payment Successful!!".tr);
// },
// onError: (error) {
// Get.back();
// ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
// },
// onCancel: (params) {
// Get.back();
// ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
// },
// ),
// ),
// );
// }
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
// Convert to int (kobo/cents)
int amountInCents = (double.parse(totalAmount) * 100).round();
await PayStackURLGen.payStackURLGen(
amount: amountInCents.toString(), //integer string
currency: "ZAR",
secretKey: payStackModel.value.secretKey.toString(),
userModel: Constant.userModel!,
).then((value) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(
PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
),
)!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
///flutter wave Payment Method
Future<void> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
setRef(); // make sure you generate reference
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {"email": Constant.userModel?.email.toString(), "phonenumber": Constant.userModel?.phoneNumber, "name": Constant.userModel?.fullName()},
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) async {
bool isVerified = await verifyFlutterWavePayment(_ref!);
if (isVerified) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
Get.back();
}
});
} else {
debugPrint('Payment initialization failed: ${response.body}');
}
}
Future<bool> verifyFlutterWavePayment(String txRef) async {
try {
final url = Uri.parse("https://api.flutterwave.com/v3/transactions/verify_by_reference?tx_ref=$txRef");
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final response = await http.get(url, headers: headers);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
if (data['status'] == 'success' && data['data']['status'] == 'successful') {
return true; // ✅ Payment confirmed
}
}
return false; // ❌ Payment not verified
} catch (e) {
debugPrint("Error verifying payment: $e");
return false;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
placeOrder();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
///Paytm payment function
Future<void> getPaytmCheckSum(context, {required double amount}) async {
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
);
final data = jsonDecode(response.body);
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
initiatePayment(amount: amount, orderId: orderId).then((value) {
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
GetPaymentTxtTokenModel result = value;
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
});
});
}
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
// try {
// var response = AllInOneSdk.startTransaction(
// paytmModel.value.paytmMID.toString(),
// orderId,
// amount.toString(),
// txnTokenBy,
// callBackURL,
// isStaging,
// true,
// true,
// );
//
// response.then((value) {
// if (value!["RESPMSG"] == "Txn Success") {
// print("txt done!!");
// ShowToastDialog.showToast("Payment Successful!!");
// placeOrder();
// }
// }).catchError((onError) {
// if (onError is PlatformException) {
// Get.back();
//
// ShowToastDialog.showToast(onError.message.toString());
// } else {
// log("======>>2");
// Get.back();
// ShowToastDialog.showToast(onError.message.toString());
// }
// });
// } catch (err) {
// Get.back();
// ShowToastDialog.showToast(err.toString());
// }
}
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
);
final data = jsonDecode(response.body);
return data['status'];
}
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required String orderId}) async {
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
String callback =
(paytmModel.value.isSandboxEnabled ?? false) ? "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId" : "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
print("INITIATE PAYMENT CALL:");
print("MID: ${paytmModel.value.paytmMID}");
print("OrderId: $orderId");
print("Amount: $amount");
print("Env: ${(paytmModel.value.isSandboxEnabled ?? false) ? "STAGING" : "LIVE"}");
final response = await http.post(
Uri.parse(initiateURL),
body: {
"mid": paytmModel.value.paytmMID ?? "",
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY ?? "",
"amount": amount.toStringAsFixed(0), // Paytm requires integer
"currency": "INR",
"callback_url": callback,
"custId": FireStoreUtils.getCurrentUid(),
"issandbox": (paytmModel.value.isSandboxEnabled ?? false) ? "1" : "0",
},
);
log("Paytm Initiate Response: ${response.body}");
final data = jsonDecode(response.body);
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
return GetPaymentTxtTokenModel.fromJson(data);
}
// Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
// String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
// String callback = "";
// if (paytmModel.value.isSandboxEnabled == true) {
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// } else {
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// }
// final response = await http.post(
// Uri.parse(initiateURL),
// headers: {},
// body: {
// "mid": paytmModel.value.paytmMID,
// "order_id": orderId,
// "key_secret": paytmModel.value.pAYTMMERCHANTKEY,
// "amount": amount.toString(),
// "currency": "INR",
// "callback_url": callback,
// "custId": FireStoreUtils.getCurrentUid(),
// "issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
// },
// );
// log(response.body);
// final data = jsonDecode(response.body);
// if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
// Get.back();
// ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
// }
// return GetPaymentTxtTokenModel.fromJson(data);
// }
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {'contact': Constant.userModel?.phoneNumber, 'email': Constant.userModel?.email},
'external': {
'wallets': ['paytm'],
},
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
final response = await http.post(
url,
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
body: jsonEncode({
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
// 🟠 ORANGE MONEY PAYMENT INTEGRATION
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
debugPrint('🟩 Starting OrangePay Payment...');
debugPrint('💰 Amount: $amount | 🆔 Order ID: $id');
ShowToastDialog.showLoader("Initializing payment...".tr);
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString().isNotEmpty) {
debugPrint('✅ Payment URL fetched successfully: $paymentURL');
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))?.then((value) async {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
debugPrint('🎉 Payment Successful for Order ID: $orderId');
if (Get.isBottomSheetOpen ?? false) Get.back();
await placeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
debugPrint('⚠️ Payment flow closed without success.');
if (Get.isBottomSheetOpen ?? false) Get.back();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
if (Get.isBottomSheetOpen ?? false) Get.back();
}
}
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
const String apiUrl = 'https://api.orange.com/oauth/v3/token';
final Map<String, String> requestBody = {'grant_type': 'client_credentials'};
debugPrint('🔐 Fetching access token from Orange API...');
debugPrint('📡 POST $apiUrl');
final response = await http.post(
Uri.parse(apiUrl),
headers: {'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
body: requestBody,
);
debugPrint('🔍 Response Code: ${response.statusCode}');
debugPrint('📨 Response Body: ${response.body}');
if (response.statusCode == 200) {
final Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'];
debugPrint('✅ Access Token Received: $accessToken');
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
debugPrint('❌ Failed to fetch access token.');
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
orderId = orderIdData;
amount = amountData;
String apiUrl = orangeMoneyModel.value.isSandbox == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
// ✅ Ensure amount formatted correctly
String formattedAmount = double.parse(amountData).toStringAsFixed(2);
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
"order_id": orderId,
"amount": formattedAmount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
"notif_url": orangeMoneyModel.value.notifyUrl ?? '',
};
debugPrint('💳 Creating Web Payment...');
debugPrint('📡 POST $apiUrl');
debugPrint('📦 Request Body: ${jsonEncode(requestBody)}');
final response = await http.post(
Uri.parse(apiUrl),
headers: {'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
debugPrint('🔍 Response Code: ${response.statusCode}');
debugPrint('📨 Response Body: ${response.body}');
if (response.statusCode == 201) {
final Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'];
debugPrint('✅ Payment Token: $payToken');
debugPrint('🌍 Payment URL: ${responseData['payment_url']}');
return responseData['payment_url'];
} else {
debugPrint('⚠️ Unexpected message: ${responseData['message']}');
return '';
}
} else {
debugPrint('❌ Payment request failed.');
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
orderId = '';
amount = '';
debugPrint('🌀 OrangePay reset completed.');
}
//XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
placeOrder();
();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

View File

@@ -0,0 +1,139 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/rating_model.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../constant/constant.dart';
import '../models/parcel_category.dart';
import '../models/parcel_order_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
class ParcelOrderDetailsController extends GetxController {
Rx<ParcelOrderModel> parcelOrder = ParcelOrderModel().obs;
RxList<ParcelCategory> parcelCategory = <ParcelCategory>[].obs;
RxBool isLoading = false.obs;
Rx<UserModel?> driverUser = Rx<UserModel?>(null);
Rx<RatingModel> ratingModel = RatingModel().obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args is ParcelOrderModel) {
parcelOrder.value = args;
setStatusHistoryFromString(parcelOrder.value);
}
loadParcelCategories();
calculateTotalAmount();
fetchDriverDetails();
}
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
void calculateTotalAmount() {
taxAmount = 0.0.obs;
discount = 0.0.obs;
subTotal.value = double.parse(parcelOrder.value.subTotal.toString());
discount.value = double.parse(parcelOrder.value.discount ?? '0.0');
for (var element in parcelOrder.value.taxSetting!) {
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
}
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
update();
}
Future<void> fetchDriverDetails() async {
if (parcelOrder.value.driverId != null) {
await FireStoreUtils.getUserProfile(parcelOrder.value.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
}
});
await FireStoreUtils.getReviewsbyID(parcelOrder.value.id.toString()).then((value) {
if (value != null) {
ratingModel.value = value;
}
});
}
}
void setStatusHistoryFromString(ParcelOrderModel order) {
final steps = ["Order Placed", "Driver Accepted", "Pickup Done", "In Transit", "Delivered"];
final history = <ParcelStatus>[];
DateTime baseTime = order.createdAt?.toDate() ?? DateTime.now();
int minutesGap = 30;
for (int i = 0; i < steps.length; i++) {
final step = steps[i];
history.add(ParcelStatus(status: step, time: baseTime.add(Duration(minutes: i * minutesGap))));
if (step == order.status) break;
}
order.statusHistory = history;
}
Future<void> cancelParcelOrder() async {
ShowToastDialog.showLoader("Cancelling order...".tr);
parcelOrder.value.status = Constant.orderCancelled;
if (parcelOrder.value.paymentMethod?.toLowerCase() != "cod") {
WalletTransactionModel walletTransaction = WalletTransactionModel(
id: Constant.getUuid(),
amount: totalAmount.value,
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: true,
orderId: parcelOrder.value.id,
note: "Refund for cancelled parcel order",
paymentStatus: "success",
serviceType: Constant.parcelServiceType,
);
// Save wallet transaction
await FireStoreUtils.setWalletTransaction(walletTransaction);
// Update wallet balance
await FireStoreUtils.updateUserWallet(amount: totalAmount.value.toString(), userId: FireStoreUtils.getCurrentUid());
}
await FireStoreUtils.parcelOrderPlace(parcelOrder.value);
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Order cancelled successfully".tr);
Get.back(result: true);
}
void loadParcelCategories() async {
isLoading.value = true;
final categories = await FireStoreUtils.getParcelServiceCategory();
parcelCategory.value = categories;
isLoading.value = false;
}
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
ParcelCategory? getSelectedCategory() {
try {
return parcelCategory.firstWhere((cat) => cat.title?.toLowerCase().trim() == parcelOrder.value.parcelType?.toLowerCase().trim(), orElse: () => ParcelCategory());
} catch (e) {
return null;
}
}
}

View File

@@ -0,0 +1,135 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/parcel_order_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/rating_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
import '../constant/constant.dart';
import '../themes/show_toast_dialog.dart';
class ParcelReviewController extends GetxController {
RxBool isLoading = true.obs;
/// Order from arguments
final Rx<ParcelOrderModel?> order = Rx<ParcelOrderModel?>(null);
/// Rating data
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
final RxDouble ratings = 0.0.obs;
final Rx<TextEditingController> comment = TextEditingController().obs;
/// Driver (to be reviewed)
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
/// Review stats
final RxInt futureCount = 0.obs;
final RxInt futureSum = 0.obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args['order'] != null) {
order.value = args['order'] as ParcelOrderModel;
getReview();
}
}
/// Fetch old review + driver stats
Future<void> getReview() async {
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0;
comment.value.text = value.comment ?? "";
}
});
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
if (ratingModel.value != null) {
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
futureCount.value = userReviewsCount - 1;
futureSum.value = userReviewsSum - oldRating;
} else {
futureCount.value = userReviewsCount;
futureSum.value = userReviewsSum;
}
}
});
isLoading.value = false;
}
/// Save / update review
Future<void> submitReview() async {
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
ShowToastDialog.showToast("Please provide rating and comment".tr);
return;
}
ShowToastDialog.showLoader("Submit in...".tr);
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
if (user != null) {
user.reviewsCount = (futureCount.value + 1).toString();
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
}
if (ratingModel.value != null && ratingModel.value!.id!.isNotEmpty) {
/// Update existing review
final updatedRating = RatingModel(
id: ratingModel.value!.id,
comment: comment.value.text,
photos: ratingModel.value?.photos ?? [],
rating: ratings.value,
orderId: ratingModel.value!.orderId,
driverId: ratingModel.value!.driverId,
customerId: ratingModel.value!.customerId,
vendorId: ratingModel.value?.vendorId,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(updatedRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
} else {
/// New review
final newRating = RatingModel(
id: Constant.getUuid(),
comment: comment.value.text,
photos: [],
rating: ratings.value,
orderId: order.value?.id,
driverId: order.value?.driverId.toString(),
customerId: Constant.userModel?.id,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(newRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
}
ShowToastDialog.closeLoader();
Get.back(result: true);
}
@override
void onClose() {
comment.value.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,40 @@
import 'package:customer/controllers/on_demand_home_controller.dart';
import 'package:get/get.dart';
import '../models/provider_serivce_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
class ProviderController extends GetxController {
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
final Rxn<UserModel> userModel = Rxn<UserModel>();
RxBool isLoading = true.obs;
late final String providerId;
Rx<OnDemandHomeController> onDemandHomeController = Get.put(OnDemandHomeController()).obs;
@override
void onInit() {
super.onInit();
//Get providerId from arguments
providerId = Get.arguments['providerId'];
getProvider();
getAuthor();
}
void getProvider() async {
FireStoreUtils.getProviderServiceByProviderId(providerId: providerId).then((catValue) {
providerList.value = catValue;
});
isLoading.value = false;
}
Future<void> getAuthor() async {
final user = await FireStoreUtils.getUserProfile(providerId);
if (user != null) {
userModel.value = user;
}
}
}

View File

@@ -0,0 +1,194 @@
import 'dart:developer';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/order_model.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../models/rating_model.dart';
import '../models/review_attribute_model.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import '../themes/show_toast_dialog.dart';
class RateProductController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Rx<TextEditingController> commentController = TextEditingController().obs;
Rx<OrderModel> orderModel = OrderModel().obs;
RxString productId = "".obs;
Rx<RatingModel> ratingModel = RatingModel().obs;
Rx<ProductModel> productModel = ProductModel().obs;
Rx<VendorModel> vendorModel = VendorModel().obs;
Rx<VendorCategoryModel> vendorCategoryModel = VendorCategoryModel().obs;
RxList<ReviewAttributeModel> reviewAttributeList = <ReviewAttributeModel>[].obs;
RxDouble ratings = 0.0.obs;
RxMap<String, dynamic> reviewAttribute = <String, dynamic>{}.obs;
RxMap<String, dynamic> reviewProductAttributes = <String, dynamic>{}.obs;
RxDouble vendorReviewSum = 0.0.obs;
RxDouble vendorReviewCount = 0.0.obs;
RxDouble productReviewSum = 0.0.obs;
RxDouble productReviewCount = 0.0.obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
orderModel.value = argumentData['orderModel'];
productId.value = argumentData['productId'];
await FireStoreUtils.getOrderReviewsByID(orderModel.value.id.toString(), productId.value).then((value) {
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0.0;
commentController.value.text = value.comment.toString();
reviewAttribute.value = value.reviewAttributes!;
images.addAll(value.photos ?? []);
}
});
await FireStoreUtils.getProductById(productId.value.split('~').first).then((value) {
if (value != null) {
productModel.value = value;
if (ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty) {
productReviewCount.value = value.reviewsCount! - 1;
productReviewSum.value = value.reviewsSum! - ratings.value;
if (value.reviewAttributes != null) {
value.reviewAttributes!.forEach((key, value) {
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute.fromJson(value);
reviewsAttributeModel.reviewsCount = reviewsAttributeModel.reviewsCount! - 1;
reviewsAttributeModel.reviewsSum = reviewsAttributeModel.reviewsSum! - reviewAttribute[key];
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
});
}
} else {
productReviewCount.value = double.parse(value.reviewsCount.toString());
productReviewSum.value = double.parse(value.reviewsSum.toString());
if (value.reviewAttributes != null) {
reviewProductAttributes.value = value.reviewAttributes!;
}
}
}
});
await FireStoreUtils.getVendorById(productModel.value.vendorID.toString()).then((value) {
if (value != null) {
vendorModel.value = value;
if (ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty) {
vendorReviewCount.value = value.reviewsCount! - 1;
vendorReviewSum.value = value.reviewsSum! - ratings.value;
} else {
vendorReviewCount.value = double.parse(value.reviewsCount.toString());
vendorReviewSum.value = double.parse(value.reviewsSum.toString());
}
}
});
await FireStoreUtils.getVendorCategoryByCategoryId(productModel.value.categoryID.toString()).then((value) async {
if (value != null) {
vendorCategoryModel.value = value;
for (var element in vendorCategoryModel.value.reviewAttributes!) {
await FireStoreUtils.getVendorReviewAttribute(element).then((value) {
reviewAttributeList.add(value!);
});
}
}
});
}
isLoading.value = false;
}
Future<void> saveRating() async {
if (ratings.value != 0.0) {
ShowToastDialog.showLoader("Please wait...".tr);
productModel.value.reviewsCount = productReviewCount.value + 1;
productModel.value.reviewsSum = productReviewSum.value + ratings.value;
productModel.value.reviewAttributes = reviewProductAttributes;
vendorModel.value.reviewsCount = vendorReviewCount.value + 1;
vendorModel.value.reviewsSum = vendorReviewSum.value + ratings.value;
if (reviewProductAttributes.isEmpty) {
reviewAttribute.forEach((key, value) {
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute(reviewsCount: 1, reviewsSum: value);
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
});
} else {
reviewProductAttributes.forEach((key, value) {
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute.fromJson(value);
reviewsAttributeModel.reviewsCount = reviewsAttributeModel.reviewsCount! + 1;
reviewsAttributeModel.reviewsSum = reviewsAttributeModel.reviewsSum! + reviewAttribute[key];
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
});
}
for (int i = 0; i < images.length; i++) {
if (images[i].runtimeType == XFile) {
String url = await Constant.uploadUserImageToFireStorage(File(images[i].path), "profileImage/${FireStoreUtils.getCurrentUid()}", File(images[i].path).path.split('/').last);
images.removeAt(i);
images.insert(i, url);
}
}
RatingModel ratingProduct = RatingModel(
productId: productId.value,
comment: commentController.value.text,
photos: images,
rating: ratings.value,
customerId: FireStoreUtils.getCurrentUid(),
id: ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty ? ratingModel.value.id : Constant.getUuid(),
orderId: orderModel.value.id,
vendorId: productModel.value.vendorID,
createdAt: Timestamp.now(),
uname: Constant.userModel!.fullName(),
profile: Constant.userModel!.profilePictureURL,
reviewAttributes: reviewAttribute,
);
print("vendor model");
log(vendorModel.value.toJson().toString());
await FireStoreUtils.updateReviewById(ratingProduct);
print("Rating Saved");
print(ratingProduct.toJson());
await FireStoreUtils.updateVendor(vendorModel.value);
await FireStoreUtils.setProduct(productModel.value);
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Rating saved successfully.".tr);
Get.back();
} else {
ShowToastDialog.showToast("Please add rate for food item.".tr);
}
}
final ImagePicker _imagePicker = ImagePicker();
RxList images = <dynamic>[].obs;
Future pickFile({required ImageSource source}) async {
try {
XFile? image = await _imagePicker.pickImage(source: source);
if (image == null) return;
images.add(image);
Get.back();
} on PlatformException catch (e) {
ShowToastDialog.showToast("Failed to Pick : \n $e");
}
}
}

View File

@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class RedeemGiftCardController extends GetxController {
Rx<TextEditingController> giftCodeController = TextEditingController().obs;
Rx<TextEditingController> giftPinController = TextEditingController().obs;
@override
void onInit() {
// TODO: implement onInit
super.onInit();
}
}

View File

@@ -0,0 +1,25 @@
import 'package:customer/models/referral_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class ReferFriendController extends GetxController {
Rx<ReferralModel> referralModel = ReferralModel().obs;
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
Future<void> getData() async {
await FireStoreUtils.getReferralUserBy().then((value) {
if (value != null) {
referralModel.value = value;
}
});
isLoading.value = false;
}
}

View File

@@ -0,0 +1,89 @@
import 'dart:math' as maths;
import 'package:customer/constant/constant.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/rental_order_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../screen_ui/rental_service/rental_dashboard_screen.dart';
import 'cab_rental_dashboard_controllers.dart';
class RentalConformationController extends GetxController {
RxBool isLoading = false.obs;
Rx<RentalOrderModel> rentalOrderModel = RentalOrderModel().obs;
Rx<TextEditingController> couponController = TextEditingController().obs;
@override
void onInit() {
getArguments();
fetchCoupons();
super.onInit();
}
void getArguments() {
final args = Get.arguments;
if (args.containsKey('rentalOrderModel') && args['rentalOrderModel'] is RentalOrderModel) {
rentalOrderModel.value = args['rentalOrderModel'] as RentalOrderModel;
calculateAmount();
} else {
debugPrint('No rental order found in arguments or invalid format.');
}
isLoading.value = false;
}
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
Rx<CouponModel> selectedCouponModel = CouponModel().obs;
void calculateAmount() {
subTotal.value = 0.0;
discount.value = 0.0;
taxAmount.value = 0.0;
totalAmount.value = 0.0;
subTotal.value = double.tryParse(rentalOrderModel.value.subTotal ?? '0') ?? 0.0;
if (selectedCouponModel.value.id != null) {
discount.value = Constant.calculateDiscount(amount: subTotal.value.toString(), offerModel: selectedCouponModel.value);
}
for (var element in rentalOrderModel.value.taxSetting ?? []) {
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
}
totalAmount.value = subTotal.value - discount.value + taxAmount.value;
}
RxList<CouponModel> couponList = <CouponModel>[].obs;
Future<void> fetchCoupons() async {
try {
await FireStoreUtils.getRentalCoupon().then((value) {
couponList.value = value;
});
} catch (e) {
print("Error fetching coupons: $e");
}
}
Future<void> placeOrder() async {
ShowToastDialog.showLoader("Placing booking...".tr);
rentalOrderModel.value.discount = discount.value.toString();
rentalOrderModel.value.couponCode = selectedCouponModel.value.code;
rentalOrderModel.value.couponId = selectedCouponModel.value.id;
rentalOrderModel.value.subTotal = subTotal.value.toString();
rentalOrderModel.value.otpCode = (maths.Random().nextInt(9000) + 1000).toString();
await FireStoreUtils.rentalOrderPlace(rentalOrderModel.value).then((value) async {
ShowToastDialog.closeLoader();
ShowToastDialog.showToast("Order placed successfully".tr);
Get.offAll(const RentalDashboardScreen());
CabRentalDashboardControllers controller = Get.put(CabRentalDashboardControllers());
controller.selectedIndex.value = 1;
// Get.back();
});
}
}

View File

@@ -0,0 +1,28 @@
import 'package:customer/models/coupon_model.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:get/get.dart';
class RentalCouponController extends GetxController{
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
void getData(){
getCouponCode();
}
RxBool isLoading = true.obs;
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
Future<void> getCouponCode() async {
await FireStoreUtils.getRentalCoupon().then((value) {
cabCouponList.value = value;
});
print("cabCouponList ${cabCouponList.length}");
isLoading.value = false;
}
}

View File

@@ -0,0 +1,237 @@
import 'dart:convert';
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/rental_order_model.dart';
import 'package:customer/models/rental_package_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/screen_ui/rental_service/rental_conformation_screen.dart';
import 'package:customer/widget/geoflutterfire/src/geoflutterfire.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as latlong;
import '../constant/constant.dart';
import '../models/payment_model/cod_setting_model.dart';
import '../models/payment_model/flutter_wave_model.dart';
import '../models/payment_model/mercado_pago_model.dart';
import '../models/payment_model/mid_trans.dart';
import '../models/payment_model/orange_money.dart';
import '../models/payment_model/pay_fast_model.dart';
import '../models/payment_model/pay_stack_model.dart';
import '../models/payment_model/paypal_model.dart';
import '../models/payment_model/paytm_model.dart';
import '../models/payment_model/razorpay_model.dart';
import '../models/payment_model/stripe_model.dart';
import '../models/payment_model/wallet_setting_model.dart';
import '../models/payment_model/xendit.dart';
import '../models/rental_vehicle_type.dart';
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
import '../utils/preferences.dart';
import '../utils/utils.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as gmaps;
class RentalHomeController extends GetxController {
RxBool isLoading = false.obs;
// Location input
final Rx<TextEditingController> sourceTextEditController = TextEditingController().obs;
// Selected date
Rx<DateTime> selectedDate = DateTime.now().obs;
// Vehicle list + selected vehicle
RxList<RentalVehicleType> vehicleTypes = <RentalVehicleType>[].obs;
Rx<RentalVehicleType?> selectedVehicleType = Rx<RentalVehicleType?>(null);
RxList<RentalPackageModel> rentalPackages = <RentalPackageModel>[].obs;
Rx<RentalPackageModel?> selectedPackage = Rx<RentalPackageModel?>(null);
Rx<UserModel> userModel = UserModel().obs;
final RxString selectedPaymentMethod = ''.obs;
final Rx<gmaps.LatLng> departureLatLong = gmaps.LatLng(0.0, 0.0).obs;
final Rx<latlong.LatLng> departureLatLongOsm = latlong.LatLng(0.0, 0.0).obs;
@override
void onInit() {
super.onInit();
if (Constant.userModel != null) {
userModel.value = Constant.userModel!;
}
getVehicleType();
fetchCurrentLocation();
}
void fetchCurrentLocation() async {
try {
Position? position = await Utils.getCurrentLocation();
if (position != null) {
Constant.currentLocation = position;
// Set default coordinates for Google or OSM
departureLatLong.value = gmaps.LatLng(position.latitude, position.longitude);
departureLatLongOsm.value = latlong.LatLng(position.latitude, position.longitude);
// Get readable address
String address = await Utils.getAddressFromCoordinates(position.latitude, position.longitude);
sourceTextEditController.value.text = address;
}
} catch (e) {
ShowToastDialog.showToast("Unable to fetch current location".tr);
}
}
/// Fetch Vehicle Types
Future<void> getVehicleType() async {
isLoading.value = true;
await FireStoreUtils.getRentalVehicleType().then((value) async {
vehicleTypes.value = value;
if (vehicleTypes.isNotEmpty) {
selectedVehicleType.value = vehicleTypes[0];
await getRentalPackage();
}
});
await getPaymentSettings();
isLoading.value = false;
}
/// Date Picker
Future<void> pickDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate.value, firstDate: DateTime.now(), lastDate: DateTime(2100));
if (picked != null) {
selectedDate.value = picked;
}
}
Future<void> getRentalPackage() async {
await FireStoreUtils.getRentalPackage(selectedVehicleType.value!.id.toString()).then((value) {
rentalPackages.value = value;
if (rentalPackages.isNotEmpty) {
selectedPackage.value = rentalPackages[0];
}
});
}
void completeOrder() {
DestinationLocation sourceLocation = DestinationLocation(
latitude: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value.latitude : departureLatLong.value.latitude,
longitude: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value.longitude : departureLatLong.value.longitude,
);
print("=====>");
print(sourceTextEditController.value.text);
RentalOrderModel rentalOrderModel = RentalOrderModel();
rentalOrderModel.id = Constant.getUuid();
rentalOrderModel.authorID = userModel.value.id;
rentalOrderModel.author = userModel.value;
rentalOrderModel.rentalVehicleType = selectedVehicleType.value;
rentalOrderModel.vehicleId = selectedVehicleType.value!.id;
rentalOrderModel.sectionId = Constant.sectionConstantModel!.id;
rentalOrderModel.sourceLocationName = sourceTextEditController.value.text;
rentalOrderModel.bookingDateTime = Timestamp.fromDate(selectedDate.value);
rentalOrderModel.paymentMethod = selectedPaymentMethod.value;
rentalOrderModel.paymentStatus = false;
rentalOrderModel.status = Constant.orderPlaced;
rentalOrderModel.subTotal = selectedPackage.value!.baseFare;
rentalOrderModel.rentalPackageModel = selectedPackage.value;
rentalOrderModel.taxSetting = Constant.taxList;
rentalOrderModel.createdAt = Timestamp.now();
rentalOrderModel.sourceLocation = sourceLocation;
rentalOrderModel.adminCommission = Constant.sectionConstantModel!.adminCommision!.amount;
rentalOrderModel.adminCommissionType = Constant.sectionConstantModel!.adminCommision!.commissionType;
rentalOrderModel.sourcePoint = G(
geopoint: GeoPoint(sourceLocation.latitude ?? 0.0, sourceLocation.longitude ?? 0.0),
geohash: Geoflutterfire().point(latitude: sourceLocation.latitude ?? 0.0, longitude: sourceLocation.longitude ?? 0.0).hash,
);
rentalOrderModel.zoneId = Constant.getZoneId(sourceLocation.latitude ?? 0.0, sourceLocation.longitude ?? 0.0);
log(rentalOrderModel.toJson().toString());
Get.back();
Get.back();
Get.to(() => RentalConformationScreen(), arguments: {"rentalOrderModel": rentalOrderModel});
}
void setDepartureMarker(double lat, double lng) {
if (Constant.selectedMapType == 'osm') {
departureLatLongOsm.value = latlong.LatLng(lat, lng);
} else {
departureLatLong.value = gmaps.LatLng(lat, lng);
}
}
// final Rx<LatLng> departureLatLong = const LatLng(0.0, 0.0).obs;
// final Rx<latlong.LatLng> departureLatLongOsm = latlong.LatLng(0.0, 0.0).obs;
// void setDepartureMarker(double lat, double long) {
// if (Constant.selectedMapType == 'osm') {
// departureLatLongOsm.value = latlong.LatLng(lat, long);
// } else {
// departureLatLong.value = LatLng(lat, long);
// }
// }
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then((value) {
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.cod.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
} else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
});
}
}

View File

@@ -0,0 +1,904 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as maths;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/payment_model/cod_setting_model.dart';
import 'package:customer/models/payment_model/flutter_wave_model.dart';
import 'package:customer/models/payment_model/mercado_pago_model.dart';
import 'package:customer/models/payment_model/mid_trans.dart';
import 'package:customer/models/payment_model/orange_money.dart';
import 'package:customer/models/payment_model/pay_fast_model.dart';
import 'package:customer/models/payment_model/pay_stack_model.dart';
import 'package:customer/models/payment_model/paypal_model.dart';
import 'package:customer/models/payment_model/paytm_model.dart';
import 'package:customer/models/payment_model/razorpay_model.dart';
import 'package:customer/models/payment_model/stripe_model.dart';
import 'package:customer/models/payment_model/wallet_setting_model.dart';
import 'package:customer/models/payment_model/xendit.dart';
import 'package:customer/models/rating_model.dart';
import 'package:customer/models/rental_order_model.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:customer/payment/MercadoPagoScreen.dart';
import 'package:customer/payment/PayFastScreen.dart';
import 'package:customer/payment/getPaytmTxtToken.dart';
import 'package:customer/payment/midtrans_screen.dart';
import 'package:customer/payment/orangePayScreen.dart';
import 'package:customer/payment/paystack/pay_stack_screen.dart';
import 'package:customer/payment/paystack/pay_stack_url_model.dart';
import 'package:customer/payment/paystack/paystack_url_genrater.dart';
import 'package:customer/payment/stripe_failed_model.dart';
import 'package:customer/payment/xenditModel.dart';
import 'package:customer/payment/xenditScreen.dart';
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:customer/utils/preferences.dart';
import 'package:flutter/material.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:uuid/uuid.dart';
import '../constant/constant.dart';
import '../models/tax_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
class RentalOrderDetailsController extends GetxController {
Rx<RentalOrderModel> order = RentalOrderModel().obs;
RxBool isLoading = true.obs;
Rx<UserModel?> driverUser = Rx<UserModel?>(null);
RxDouble subTotal = 0.0.obs;
RxDouble discount = 0.0.obs;
RxDouble taxAmount = 0.0.obs;
RxDouble totalAmount = 0.0.obs;
RxDouble extraKilometerCharge = 0.0.obs;
RxDouble extraMinutesCharge = 0.0.obs;
final RxString selectedPaymentMethod = ''.obs;
Rx<RatingModel> ratingModel = RatingModel().obs;
@override
void onInit() {
getData();
super.onInit();
}
Future<void> getData() async {
final args = Get.arguments;
if (args != null) {
order.value = args as RentalOrderModel;
calculateTotalAmount();
await fetchDriverDetails();
await getPaymentSettings();
}
isLoading.value = false;
}
Future<void> fetchDriverDetails() async {
if (order.value.driverId != null) {
await FireStoreUtils.getUserProfile(order.value.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
}
});
await FireStoreUtils.getReviewsbyID(order.value.id.toString()).then((value) {
if (value != null) {
ratingModel.value = value;
}
});
}
}
String getExtraKm() {
try {
final double start = double.tryParse(order.value.startKitoMetersReading ?? '0') ?? 0.0;
final double end = double.tryParse(order.value.endKitoMetersReading ?? '0') ?? 0.0;
final double included = double.tryParse(order.value.rentalPackageModel?.includedDistance?.toString() ?? '0') ?? 0.0;
// Calculate extra km safely
final double extra = (end - start - included);
final double validExtra = extra > 0 ? extra : 0;
return "${validExtra.toStringAsFixed(2)} ${Constant.distanceType}";
} catch (e) {
return "0 ${Constant.distanceType}";
}
}
///Safe calculation after order is loaded
void calculateTotalAmount() {
try {
subTotal.value = double.tryParse(order.value.subTotal?.toString() ?? "0") ?? 0.0;
discount.value = double.tryParse(order.value.discount?.toString() ?? "0") ?? 0.0;
taxAmount.value = 0.0;
if (order.value.endTime != null) {
DateTime start = order.value.startTime!.toDate();
DateTime end = order.value.endTime!.toDate();
// Total rented minutes
int totalMinutes = end.difference(start).inMinutes;
int includedMinutes = (int.tryParse(order.value.rentalPackageModel?.includedHours.toString() ?? "0") ?? 0) * 60;
if (totalMinutes > includedMinutes) {
int extraMinutes = totalMinutes - includedMinutes;
double minuteFare = double.tryParse(order.value.rentalPackageModel?.extraMinuteFare?.toString() ?? "0") ?? 0.0;
extraMinutesCharge.value = extraMinutes * minuteFare;
} else {
extraMinutesCharge.value = 0;
}
}
if (order.value.startKitoMetersReading != null && order.value.endKitoMetersReading != null) {
double startKm = double.tryParse(order.value.startKitoMetersReading?.toString() ?? "0") ?? 0.0;
double endKm = double.tryParse(order.value.endKitoMetersReading?.toString() ?? "0") ?? 0.0;
if (endKm > startKm) {
double totalKm = endKm - startKm;
if (totalKm > double.parse(order.value.rentalPackageModel!.includedDistance!)) {
totalKm = totalKm - double.parse(order.value.rentalPackageModel!.includedDistance!);
double extraKmRate = double.tryParse(order.value.rentalPackageModel?.extraKmFare?.toString() ?? "0") ?? 0.0;
extraKilometerCharge.value = totalKm * extraKmRate;
}
}
}
subTotal.value = subTotal.value + extraKilometerCharge.value + extraMinutesCharge.value;
if (order.value.taxSetting != null) {
for (var element in order.value.taxSetting!) {
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
}
}
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
} catch (e) {
ShowToastDialog.showToast("${'Failed to calculate total:'.tr} $e");
}
}
Future<void> completeOrder() async {
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
order.value.paymentMethod = selectedPaymentMethod.value;
await FireStoreUtils.rentalOrderPlace(order.value).then((value) {
ShowToastDialog.showToast("Payment method changed".tr);
Get.back();
Get.back();
});
} else {
order.value.paymentStatus = true;
order.value.paymentMethod = selectedPaymentMethod.value;
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(totalAmount.toString()),
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: false,
orderId: order.value.id,
note: "Rental Amount debited",
paymentStatus: "success",
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.toString()}", userId: FireStoreUtils.getCurrentUid());
}
});
}
await FireStoreUtils.rentalOrderPlace(order.value).then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
Get.back();
Get.back();
});
}
}
Future<void> cancelRentalRequest(RentalOrderModel order, {List<TaxModel>? taxList}) async {
try {
isLoading.value = true;
order.status = Constant.orderCancelled;
await FireStoreUtils.rentalOrderPlace(order);
if (order.paymentMethod?.toLowerCase() != "cod") {
double totalTax = 0.0;
if (taxList != null) {
for (var element in taxList) {
totalTax += Constant.calculateTax(amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(), taxModel: element);
}
}
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
double refundAmount = subTotal + totalTax;
WalletTransactionModel walletTransaction = WalletTransactionModel(
id: Constant.getUuid(),
amount: refundAmount,
date: Timestamp.now(),
paymentMethod: PaymentGateway.wallet.name,
transactionUser: "customer",
userId: FireStoreUtils.getCurrentUid(),
isTopup: true,
// refund
orderId: order.id,
note: "Refund for cancelled booking",
paymentStatus: "success",
serviceType: Constant.parcelServiceType,
);
await FireStoreUtils.setWalletTransaction(walletTransaction);
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
}
ShowToastDialog.showToast("Booking cancelled successfully".tr);
Get.back();
} catch (e) {
ShowToastDialog.showToast("${'Failed to cancel booking:'.tr} $e".tr);
} finally {
isLoading.value = false;
}
}
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<PaytmModel> paytmModel = PaytmModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then((value) {
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
if (walletSettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.wallet.name;
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.cod.name;
} else if (stripeModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.stripe.name;
} else if (payPalModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.paypal.name;
} else if (payStackModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payStack.name;
} else if (mercadoPagoModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
} else if (flutterWaveModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
} else if (payFastModel.value.isEnable == true) {
selectedPaymentMethod.value = PaymentGateway.payFast.name;
} else if (razorPayModel.value.isEnabled == true) {
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
} else if (midTransModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
} else if (orangeMoneyModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
} else if (xenditModel.value.enable == true) {
selectedPaymentMethod.value = PaymentGateway.xendit.name;
}
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'eMart Customer';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
});
}
// Strip
Future<void> stripeMakePayment({required String amount}) async {
log(double.parse(amount).toStringAsFixed(0));
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
log("stripe Responce====>$paymentIntentData");
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
merchantDisplayName: 'GoRide',
),
);
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
log("$e \n$s");
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
completeOrder();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": Constant.userModel!.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
);
return jsonDecode(response.body);
} catch (e) {
log(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
},
],
"payer": {"email": Constant.userModel!.email},
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
"auto_return": "approved",
// Automatically return after payment is approved
});
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Error creating preference: ${response.body}');
return null;
}
}
//Paypal
void paypalPaymentSheet(String amount, context) {
Navigator.of(context).push(
MaterialPageRoute(
builder:
(BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.parkme://paypalpay",
cancelURL: "com.parkme://paypalpay",
transactions: [
{
"amount": {
"total": amount,
"currency": "USD",
"details": {"subtotal": amount},
},
},
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
completeOrder();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
),
),
);
}
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
await PayStackURLGen.payStackURLGen(
amount: (double.parse(totalAmount) * 100).toString(),
currency: "ZAR",
secretKey: payStackModel.value.secretKey.toString(),
userModel: Constant.userModel!,
).then((value) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(
PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
),
)!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
//flutter wave Payment Method
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {
"email": Constant.userModel!.email.toString(),
"phonenumber": Constant.userModel!.phoneNumber, // Add a real phone number
"name": Constant.userModel!.fullName(), // Add a real customer name
},
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Payment initialization failed: ${response.body}');
return null;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
completeOrder();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
///Paytm payment function
Future<void> getPaytmCheckSum(context, {required double amount}) async {
// final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
// String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
//
// final response = await http.post(
// Uri.parse(getChecksum),
// headers: {},
// body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
// );
//
// final data = jsonDecode(response.body);
// await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
// initiatePayment(amount: amount, orderId: orderId).then((value) {
// String callback = "";
// if (paytmModel.value.isSandboxEnabled == true) {
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// } else {
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
// }
//
// GetPaymentTxtTokenModel result = value;
// startTransaction(context, txnTokenBy: result.body.txnToken, orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
// });
// });
}
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
// try {
// var response = AllInOneSdk.startTransaction(
// paytmModel.value.paytmMID.toString(),
// orderId,
// amount.toString(),
// txnTokenBy,
// callBackURL,
// isStaging,
// true,
// true,
// );
//
// response.then((value) {
// if (value!["RESPMSG"] == "Txn Success") {
// print("txt done!!");
// ShowToastDialog.showToast("Payment Successful!!");
// completeOrder();
// }
// }).catchError((onError) {
// if (onError is PlatformException) {
// Get.back();
//
// ShowToastDialog.showToast(onError.message.toString());
// } else {
// log("======>>2");
// Get.back();
// ShowToastDialog.showToast(onError.message.toString());
// }
// });
// } catch (err) {
// Get.back();
// ShowToastDialog.showToast(err.toString());
// }
}
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
final response = await http.post(
Uri.parse(getChecksum),
headers: {},
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
);
final data = jsonDecode(response.body);
return data['status'];
}
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
String callback = "";
if (paytmModel.value.isSandboxEnabled == true) {
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
} else {
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
}
final response = await http.post(
Uri.parse(initiateURL),
headers: {},
body: {
"mid": paytmModel.value.paytmMID,
"order_id": orderId,
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
"amount": amount.toString(),
"currency": "INR",
"callback_url": callback,
"custId": FireStoreUtils.getCurrentUid(),
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
},
);
log(response.body);
final data = jsonDecode(response.body);
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
Get.back();
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
}
return GetPaymentTxtTokenModel.fromJson(data);
}
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {'contact': Constant.userModel!.phoneNumber, 'email': Constant.userModel!.email},
'external': {
'wallets': ['paytm'],
},
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
final currentDate = DateTime.now();
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
final response = await http.post(
url,
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
body: jsonEncode({
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
//Orangepay payment
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString() != '') {
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
}
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
String apiUrl = 'https://api.orange.com/oauth/v3/token';
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
body: requestBody,
);
// Handle the response
if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'];
// ignore: use_build_context_synchronously
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
orderId = orderIdData;
amount = amountData;
String apiUrl = orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
"order_id": orderId,
"amount": amount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
// Handle the response
if (response.statusCode == 201) {
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'];
return responseData['payment_url'];
} else {
return '';
}
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
amount = '';
}
//XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
completeOrder();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

View File

@@ -0,0 +1,137 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constant/collection_name.dart';
import '../models/rating_model.dart';
import '../models/rental_order_model.dart';
import '../models/user_model.dart';
import '../service/fire_store_utils.dart';
import '../constant/constant.dart';
import '../themes/show_toast_dialog.dart';
class RentalReviewController extends GetxController {
RxBool isLoading = true.obs;
/// Order from arguments
final Rx<RentalOrderModel?> order = Rx<RentalOrderModel?>(null);
/// Rating data
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
final RxDouble ratings = 0.0.obs;
final Rx<TextEditingController> comment = TextEditingController().obs;
/// Driver (to be reviewed)
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
/// Review stats
final RxInt futureCount = 0.obs;
final RxInt futureSum = 0.obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments;
if (args != null && args['order'] != null) {
order.value = args['order'] as RentalOrderModel;
getReview();
}
}
/// Fetch old review + driver stats
Future<void> getReview() async {
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
if (value != null) {
ratingModel.value = value;
ratings.value = value.rating ?? 0;
comment.value.text = value.comment ?? "";
}
});
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
if (value != null) {
driverUser.value = value;
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
if (ratingModel.value != null) {
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
futureCount.value = userReviewsCount - 1;
futureSum.value = userReviewsSum - oldRating;
} else {
futureCount.value = userReviewsCount;
futureSum.value = userReviewsSum;
}
}
});
isLoading.value = false;
}
/// Save / update review
Future<void> submitReview() async {
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
ShowToastDialog.showToast("Please provide rating and comment".tr);
return;
}
ShowToastDialog.showLoader("Submit in...".tr);
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
if (user != null) {
user.reviewsCount = (futureCount.value + 1).toString();
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
}
if (ratingModel.value != null) {
/// Update existing review
final updatedRating = RatingModel(
id: ratingModel.value!.id,
comment: comment.value.text,
photos: ratingModel.value?.photos ?? [],
rating: ratings.value,
orderId: ratingModel.value!.orderId,
driverId: ratingModel.value!.driverId,
customerId: ratingModel.value!.customerId,
vendorId: ratingModel.value?.vendorId,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(updatedRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
} else {
/// New review
final docRef = FireStoreUtils.fireStore.collection(CollectionName.itemsReview).doc();
final newRating = RatingModel(
id: docRef.id,
comment: comment.value.text,
photos: [],
rating: ratings.value,
orderId: order.value?.id,
driverId: order.value?.driverId.toString(),
customerId: Constant.userModel?.id,
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
profile: Constant.userModel?.profilePictureURL,
createdAt: Timestamp.now(),
);
await FireStoreUtils.updateReviewById(newRating);
if (user != null) {
await FireStoreUtils.updateUser(user);
}
}
ShowToastDialog.closeLoader();
Get.back(result: true);
}
@override
void onClose() {
comment.value.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,300 @@
import 'dart:async';
import 'dart:developer';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/brands_model.dart';
import 'package:customer/models/cart_product_model.dart';
import 'package:customer/models/coupon_model.dart';
import 'package:customer/models/favourite_item_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../models/attributes_model.dart';
import '../service/cart_provider.dart';
import '../service/fire_store_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
class RestaurantDetailsController extends GetxController {
Rx<TextEditingController> searchEditingController = TextEditingController().obs;
RxBool isLoading = true.obs;
Rx<PageController> pageController = PageController().obs;
RxInt currentPage = 0.obs;
RxBool isVag = false.obs;
RxBool isNonVag = false.obs;
RxBool isMenuOpen = false.obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
RxList<FavouriteItemModel> favouriteItemList = <FavouriteItemModel>[].obs;
RxList<ProductModel> allProductList = <ProductModel>[].obs;
RxList<ProductModel> productList = <ProductModel>[].obs;
RxList<VendorCategoryModel> vendorCategoryList = <VendorCategoryModel>[].obs;
RxList<CouponModel> couponList = <CouponModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
void animateSlider() {
if (vendorModel.value.photos != null && vendorModel.value.photos!.isNotEmpty) {
Timer.periodic(const Duration(seconds: 2), (Timer timer) {
if (currentPage < vendorModel.value.photos!.length - 1) {
currentPage++;
} else {
currentPage.value = 0;
}
if (pageController.value.hasClients) {
pageController.value.animateToPage(currentPage.value, duration: const Duration(milliseconds: 300), curve: Curves.easeIn);
}
});
}
}
Rx<VendorModel> vendorModel = VendorModel().obs;
final CartProvider cartProvider = CartProvider();
Future<void> getArgument() async {
cartProvider.cartStream.listen((event) async {
cartItem.clear();
cartItem.addAll(event);
});
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorModel.value = argumentData['vendorModel'];
}
animateSlider();
statusCheck();
await getProduct();
isLoading.value = false;
await getFavouriteList();
update();
}
RxList<BrandsModel> brandList = <BrandsModel>[].obs;
Future<void> getProduct() async {
await FireStoreUtils.getProductByVendorId(vendorModel.value.id.toString()).then((value) {
if ((Constant.isSubscriptionModelApplied == true || vendorModel.value.adminCommission?.isEnabled == true) && vendorModel.value.subscriptionPlan != null) {
if (vendorModel.value.subscriptionPlan?.itemLimit == '-1') {
allProductList.value = value;
productList.value = value;
} else {
int selectedProduct =
value.length < int.parse(vendorModel.value.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(vendorModel.value.subscriptionPlan?.itemLimit ?? '0');
allProductList.value = value.sublist(0, selectedProduct);
productList.value = value.sublist(0, selectedProduct);
}
} else {
allProductList.value = value;
productList.value = value;
}
});
for (var element in productList) {
await FireStoreUtils.getVendorCategoryById(element.categoryID.toString()).then((value) {
if (value != null) {
vendorCategoryList.add(value);
}
});
}
await FireStoreUtils.getBrandList().then((value) {
brandList.value = value;
});
var seen = <String>{};
vendorCategoryList.value = vendorCategoryList.where((element) => seen.add(element.id.toString())).toList();
}
void searchProduct(String name) {
if (name.isEmpty) {
productList.clear();
productList.addAll(allProductList);
} else {
isVag.value = false;
isNonVag.value = false;
productList.value = allProductList.where((p0) => p0.name!.toLowerCase().contains(name.toLowerCase())).toList();
}
update();
}
void filterRecord() {
if (isVag.value == true && isNonVag.value == true) {
productList.value = allProductList.where((p0) => p0.nonveg == true || p0.nonveg == false).toList();
} else if (isVag.value == true && isNonVag.value == false) {
productList.value = allProductList.where((p0) => p0.nonveg == false).toList();
} else if (isVag.value == false && isNonVag.value == true) {
productList.value = allProductList.where((p0) => p0.nonveg == true).toList();
} else if (isVag.value == false && isNonVag.value == false) {
productList.value = allProductList.where((p0) => p0.nonveg == true || p0.nonveg == false).toList();
}
}
Future<List<ProductModel>> getProductByCategory(VendorCategoryModel vendorCategoryModel) async {
return productList.where((p0) => p0.categoryID == vendorCategoryModel.id).toList();
}
Future<void> getFavouriteList() async {
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
await FireStoreUtils.getFavouriteItem().then((value) {
favouriteItemList.value = value;
});
await FireStoreUtils.getOfferByVendorId(vendorModel.value.id.toString()).then((value) {
couponList.value = value;
});
}
await getAttributeData();
update();
}
RxBool isOpen = false.obs;
void statusCheck() {
final now = DateTime.now();
var day = DateFormat('EEEE', 'en_US').format(now);
var date = DateFormat('dd-MM-yyyy').format(now);
for (var element in vendorModel.value.workingHours ?? []) {
if (day == element.day.toString()) {
if (element.timeslot!.isNotEmpty) {
for (var element in element.timeslot!) {
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
if (isCurrentDateInRange(start, end)) {
isOpen.value = true;
}
}
}
}
}
}
String getBrandName(String brandId) {
String brandName = '';
for (var element in brandList) {
if (element.id == brandId) {
brandName = element.title ?? '';
}
}
return brandName;
}
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
print(startDate);
print(endDate);
final currentDate = DateTime.now();
print(currentDate);
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
}
RxList<AttributesModel> attributesList = <AttributesModel>[].obs;
RxList selectedVariants = [].obs;
RxList selectedIndexVariants = [].obs;
RxList selectedIndexArray = [].obs;
RxList selectedAddOns = [].obs;
RxInt quantity = 1.obs;
String calculatePrice(ProductModel productModel) {
String mainPrice = "0";
String variantPrice = "0";
String adOnsPrice = "0";
if (productModel.itemAttribute != null) {
if (productModel.itemAttribute!.variants!.where((element) => element.variantSku == selectedVariants.join('-')).isNotEmpty) {
variantPrice = Constant.productCommissionPrice(
vendorModel.value,
productModel.itemAttribute!.variants!.where((element) => element.variantSku == selectedVariants.join('-')).first.variantPrice ?? '0',
);
}
} else {
String price = Constant.productCommissionPrice(vendorModel.value, productModel.price.toString());
String disPrice = double.parse(productModel.disPrice.toString()) <= 0 ? "0" : Constant.productCommissionPrice(vendorModel.value, productModel.disPrice.toString());
if (double.parse(disPrice) <= 0) {
variantPrice = price;
} else {
variantPrice = disPrice;
}
}
for (int i = 0; i < productModel.addOnsPrice!.length; i++) {
if (selectedAddOns.contains(productModel.addOnsTitle![i]) == true) {
adOnsPrice = (double.parse(adOnsPrice.toString()) + double.parse(Constant.productCommissionPrice(vendorModel.value, productModel.addOnsPrice![i].toString()))).toString();
}
}
adOnsPrice = (quantity.value * double.parse(adOnsPrice)).toString();
mainPrice = ((double.parse(variantPrice.toString()) * double.parse(quantity.value.toString())) + double.parse(adOnsPrice.toString())).toString();
return mainPrice;
}
Future<void> getAttributeData() async {
await FireStoreUtils.getAttributes().then((value) {
if (value != null) {
attributesList.value = value;
}
});
}
Future<void> addToCart({required ProductModel productModel, required String price, required String discountPrice, required bool isIncrement, required int quantity, VariantInfo? variantInfo}) async {
CartProductModel cartProductModel = CartProductModel();
String adOnsPrice = "0";
for (int i = 0; i < productModel.addOnsPrice!.length; i++) {
if (selectedAddOns.contains(productModel.addOnsTitle![i]) == true && productModel.addOnsPrice![i] != '0') {
adOnsPrice = (double.parse(adOnsPrice.toString()) + double.parse(Constant.productCommissionPrice(vendorModel.value, productModel.addOnsPrice![i].toString()))).toString();
}
}
if (variantInfo != null) {
cartProductModel.id = "${productModel.id!}~${variantInfo.variantId.toString()}";
cartProductModel.name = productModel.name!;
cartProductModel.photo = productModel.photo!;
cartProductModel.categoryId = productModel.categoryID!;
cartProductModel.price = price;
cartProductModel.discountPrice = discountPrice;
cartProductModel.vendorID = vendorModel.value.id;
cartProductModel.quantity = quantity;
cartProductModel.variantInfo = variantInfo;
cartProductModel.extrasPrice = adOnsPrice;
cartProductModel.extras = selectedAddOns.isEmpty ? [] : selectedAddOns;
} else {
cartProductModel.id = productModel.id!;
cartProductModel.name = productModel.name!;
cartProductModel.photo = productModel.photo!;
cartProductModel.categoryId = productModel.categoryID!;
cartProductModel.price = price;
cartProductModel.discountPrice = discountPrice;
cartProductModel.vendorID = vendorModel.value.id;
cartProductModel.quantity = quantity;
cartProductModel.variantInfo = VariantInfo();
cartProductModel.extrasPrice = adOnsPrice;
cartProductModel.extras = selectedAddOns.isEmpty ? [] : selectedAddOns;
}
if (isIncrement) {
await cartProvider.addToCart(Get.context!, cartProductModel, quantity);
} else {
await cartProvider.removeFromCart(cartProductModel, quantity);
}
log("===> new ${cartItem.length}");
update();
}
}

View File

@@ -0,0 +1,49 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class RestaurantListController extends GetxController {
RxBool isLoading = true.obs;
RxList<VendorModel> vendorList = <VendorModel>[].obs;
RxList<VendorModel> vendorSearchList = <VendorModel>[].obs;
RxString title = "Restaurants".obs;
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorList.value = argumentData['vendorList'];
vendorSearchList.value = argumentData['vendorList'];
title.value = argumentData['title'] ?? "Restaurants";
}
await getFavouriteRestaurant();
isLoading.value = false;
}
Future<void> getFavouriteRestaurant() async {
if (Constant.userModel != null) {
await FireStoreUtils.getFavouriteRestaurant().then((value) {
favouriteList.value = value;
});
}
}
@override
void dispose() {
vendorSearchList.clear();
super.dispose();
}
}

View File

@@ -0,0 +1,36 @@
import 'package:customer/models/rating_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class ReviewListController extends GetxController {
RxBool isLoading = true.obs;
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
Rx<VendorModel> vendorModel = VendorModel().obs;
RxList<RatingModel> ratingList = <RatingModel>[].obs;
void getArgument() {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorModel.value = argumentData['vendorModel'];
getAllReview();
}
isLoading.value = false;
}
Future<void> getAllReview() async {
await FireStoreUtils.getVendorReviews(vendorModel.value.id.toString()).then(
(value) {
ratingList.value = value;
},
);
update();
}
}

View File

@@ -0,0 +1,26 @@
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class ScanQrCodeController extends GetxController {
@override
void onInit() {
// TODO: implement onInit
getData();
super.onInit();
}
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
void getData() {
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
allNearestRestaurant.addAll(event);
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}

View File

@@ -0,0 +1,72 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/vendor_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class SearchScreenController extends GetxController {
@override
void onInit() {
// TODO: implement onInit
getArgument();
super.onInit();
}
RxBool isLoading = true.obs;
RxList<VendorModel> vendorList = <VendorModel>[].obs;
RxList<VendorModel> vendorSearchList = <VendorModel>[].obs;
RxList<ProductModel> productList = <ProductModel>[].obs;
RxList<ProductModel> productSearchList = <ProductModel>[].obs;
Future<void> getArgument() async {
dynamic argumentData = Get.arguments;
if (argumentData != null) {
vendorList.value = argumentData['vendorList'];
productList.clear();
}
isLoading.value = false;
for (var element in vendorList) {
await FireStoreUtils.getProductByVendorId(element.id.toString()).then((value) {
if ((Constant.isSubscriptionModelApplied == true || element.adminCommission?.isEnabled == true) && element.subscriptionPlan != null) {
if (element.subscriptionPlan?.itemLimit == '-1') {
productList.addAll(value);
} else {
int selectedProduct =
value.length < int.parse(element.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(element.subscriptionPlan?.itemLimit ?? '0');
productList.addAll(value.sublist(0, selectedProduct));
}
} else {
productList.addAll(value);
}
});
}
}
void onSearchTextChanged(String text) {
if (text.isEmpty) {
return;
}
vendorSearchList.clear();
productSearchList.clear();
for (var element in vendorList) {
if (element.title!.toLowerCase().contains(text.toLowerCase())) {
vendorSearchList.add(element);
}
}
for (var element in productList) {
if (element.name!.toLowerCase().contains(text.toLowerCase())) {
productSearchList.add(element);
}
}
}
@override
void dispose() {
vendorSearchList.clear();
productSearchList.clear();
super.dispose();
}
}

View File

@@ -0,0 +1,180 @@
import 'package:customer/models/section_model.dart';
import 'package:customer/screen_ui/cab_service_screens/cab_dashboard_screen.dart';
import 'package:customer/screen_ui/ecommarce/dash_board_e_commerce_screen.dart';
import 'package:customer/screen_ui/parcel_service/parcel_dashboard_screen.dart';
import 'package:customer/screen_ui/rental_service/rental_dashboard_screen.dart';
import 'package:customer/service/cart_provider.dart';
import 'package:customer/service/database_helper.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/currency_model.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:customer/themes/round_button_fill.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../screen_ui/auth_screens/login_screen.dart';
import '../screen_ui/multi_vendor_service/dash_board_screens/dash_board_screen.dart';
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
import '../service/notification_service.dart';
class ServiceListController extends GetxController {
var isLoading = false.obs;
var serviceListBanner = <dynamic>[].obs;
var sectionList = <SectionModel>[].obs;
var currencyData = CurrencyModel().obs;
@override
void onInit() {
super.onInit();
loadData();
}
Future<void> loadData() async {
isLoading.value = true;
// fetch currency
CurrencyModel? currency = await FireStoreUtils.getCurrency();
currencyData.value = currency ?? CurrencyModel(id: "", code: "USD", decimal: 2, isactive: true, name: "US Dollar", symbol: "\$", symbolatright: false);
// Load sections
List<SectionModel> sections = await FireStoreUtils.getSections();
sectionList.assignAll(sections);
await FireStoreUtils.getSectionBannerList().then((value) {
serviceListBanner.assignAll(value);
});
await getZone();
isLoading.value = false;
}
Future<void> getZone() async {
await FireStoreUtils.getZone().then((value) {
if (value != null) {
Constant.zoneList = value;
}
});
}
Future<void> onServiceTap(BuildContext context, SectionModel sectionModel) async {
try {
ShowToastDialog.showLoader("Please wait...".tr);
Constant.sectionConstantModel = sectionModel;
AppThemeData.primary300 = Color(int.tryParse(sectionModel.color?.replaceFirst("#", "0xff") ?? '') ?? 0xff2196F3);
if (auth.FirebaseAuth.instance.currentUser != null) {
String uid = auth.FirebaseAuth.instance.currentUser!.uid;
UserModel? user = await FireStoreUtils.getUserProfile(uid);
if (user != null && user.role == Constant.userRoleCustomer) {
user.fcmToken = await NotificationService.getToken();
await FireStoreUtils.updateUser(user);
ShowToastDialog.closeLoader();
await _navigate(sectionModel);
} else {
ShowToastDialog.closeLoader();
Get.offAll(() => const LoginScreen());
}
} else {
ShowToastDialog.closeLoader();
await _navigate(sectionModel);
}
} catch (e) {
print("Error during service tap: $e");
ShowToastDialog.closeLoader();
}
}
Future<void> _navigate(SectionModel sectionModel) async {
await FireStoreUtils.getTaxList(sectionModel.id ?? "").then((value) {
if (value != null) {
Constant.taxList = value;
}
});
if (sectionModel.serviceTypeFlag == "ecommerce-service" || sectionModel.serviceTypeFlag == "delivery-service") {
if (cartItem.isNotEmpty) {
showAlertDialog(Get.context!, UserModel(), sectionModel);
} else {
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
Get.to(DashBoardEcommerceScreen());
} else if (sectionModel.serviceTypeFlag == "cab-service") {
Get.to(CabDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "rental-service") {
Get.to(RentalDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "parcel_delivery") {
Get.to(ParcelDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "ondemand-service") {
Get.to(OnDemandDashboardScreen());
} else {
Get.to(() => DashBoardScreen());
}
}
} else {
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
Get.to(DashBoardEcommerceScreen());
} else if (sectionModel.serviceTypeFlag == "cab-service") {
Get.to(CabDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "rental-service") {
Get.to(RentalDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "parcel_delivery") {
Get.to(ParcelDashboardScreen());
} else if (sectionModel.serviceTypeFlag == "ondemand-service") {
Get.to(OnDemandDashboardScreen());
} else {
Get.to(() => DashBoardScreen());
}
}
}
final CartProvider cartProvider = CartProvider();
void showAlertDialog(BuildContext context, UserModel user, SectionModel sectionModel) {
Get.defaultDialog(
title: "Alert!",
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("If you select this Section/Service, your previously added items will be removed from the cart.".tr, textAlign: TextAlign.center),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: RoundedButtonFill(
height: 5.5,
title: "Cancel".tr,
onPress: () {
Get.back();
},
color: AppThemeData.grey900,
textColor: AppThemeData.surface,
),
),
const SizedBox(width: 12),
Expanded(
child: RoundedButtonFill(
title: "OK".tr,
height: 5.5,
onPress: () async {
DatabaseHelper.instance.deleteAllCartProducts();
cartProvider.clearDatabase();
Get.back();
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
Get.off(() => DashBoardEcommerceScreen());
} else {
Get.to(() => DashBoardScreen());
}
},
color: AppThemeData.primary300,
textColor: AppThemeData.surface,
),
),
],
),
],
),
actions: [], // 👈 keep this empty since we put buttons in content
);
}
}

View File

@@ -0,0 +1,195 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import '../constant/constant.dart';
import '../models/referral_model.dart';
import '../screen_ui/service_home_screen/service_list_screen.dart';
import '../service/fire_store_utils.dart';
import '../themes/show_toast_dialog.dart';
import '../utils/notification_service.dart';
class SignUpController extends GetxController {
Rx<TextEditingController> firstNameController = TextEditingController().obs;
Rx<TextEditingController> lastNameController = TextEditingController().obs;
Rx<TextEditingController> emailController = TextEditingController().obs;
Rx<TextEditingController> mobileController = TextEditingController().obs;
Rx<TextEditingController> countryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
Rx<TextEditingController> passwordController = TextEditingController().obs;
Rx<TextEditingController> confirmPasswordController = TextEditingController().obs;
Rx<TextEditingController> referralController = TextEditingController().obs;
final FocusNode emailFocusNode = FocusNode();
final FocusNode passwordFocusNode = FocusNode();
// State
final RxBool isLoading = false.obs;
final auth.FirebaseAuth _firebaseAuth = auth.FirebaseAuth.instance;
RxString type = "email".obs;
Rx<UserModel> userModel = UserModel().obs;
RxBool passwordVisible = true.obs;
RxBool conformPasswordVisible = true.obs;
@override
void onInit() {
super.onInit();
getArgument();
}
void getArgument() {
final args = Get.arguments;
type.value = args?['type'] ?? 'email';
userModel.value = args?['userModel'] ?? UserModel();
//Pre-fill fields for Google/Apple signup
if (type.value == "google" || type.value == "apple") {
firstNameController.value.text = userModel.value.firstName ?? "";
lastNameController.value.text = userModel.value.lastName ?? "";
emailController.value.text = userModel.value.email ?? "";
}
//mobile number signup
if (type.value == "mobileNumber") {
mobileController.value.text = userModel.value.phoneNumber ?? "";
countryCodeController.value.text = userModel.value.countryCode ?? "";
}
}
/// Main Sign-Up Trigger
void signUp() async {
debugPrint("SIGNUP CALLED!");
try {
if (!_validateInputs()) return;
ShowToastDialog.showLoader("Creating account...".tr);
if (type.value == "mobileNumber") {
await _signUpWithMobile();
} else {
await _signUpWithEmail();
}
ShowToastDialog.closeLoader();
} catch (e, st) {
ShowToastDialog.closeLoader();
debugPrint("SIGNUP OUTER EXCEPTION: $e\n$st");
ShowToastDialog.showToast("${'signup_failed'.tr}: $e");
}
}
/// Validation Logic
bool _validateInputs() {
if (firstNameController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter first name".tr);
return false;
} else if (lastNameController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter last name".tr);
return false;
} else if (emailController.value.text.isEmpty || !emailController.value.text.isEmail) {
ShowToastDialog.showToast("Please enter a valid email address".tr);
return false;
} else if (mobileController.value.text.isEmpty) {
ShowToastDialog.showToast("Please enter a valid phone number".tr);
return false;
} else if (passwordController.value.text.length < 6) {
ShowToastDialog.showToast("Password must be at least 6 characters".tr);
return false;
} else if (passwordController.value.text != confirmPasswordController.value.text) {
ShowToastDialog.showToast("Password and Confirm password do not match".tr);
return false;
}
return true;
}
/// Email Sign-up Flow
Future<void> _signUpWithEmail() async {
try {
final credential = await _firebaseAuth.createUserWithEmailAndPassword(email: emailController.value.text.trim(), password: passwordController.value.text.trim());
if (credential.user != null) {
final newUser = await _buildUserModel(credential.user?.uid ?? '');
await _handleReferral(newUser.id ?? '');
await FireStoreUtils.updateUser(newUser);
// appController.currentUser.value = newUser;
_navigateBasedOnAddress(newUser);
}
} on auth.FirebaseAuthException catch (e) {
debugPrint("FirebaseAuthException caught: code=${e.code}, message=${e.message}");
if (e.code == 'email-already-in-use') {
ShowToastDialog.showToast("Email already in use".tr);
} else if (e.code == 'weak-password') {
ShowToastDialog.showToast("Password is too weak".tr);
} else if (e.code == 'invalid-email') {
ShowToastDialog.showToast("Invalid email address".tr);
} else {
ShowToastDialog.showToast(e.message ?? "signup_failed".tr);
}
} catch (e) {
debugPrint("Something went wrong: ${e.toString()}");
ShowToastDialog.showToast("${'something_went_wrong'.tr}: ${e.toString()}");
}
}
/// Mobile Sign-up Flow
Future<void> _signUpWithMobile() async {
debugPrint("Signup with mobile called...");
try {
final uid = FireStoreUtils.getCurrentUid();
userModel.value = await _buildUserModel(uid);
await _handleReferral(uid);
await FireStoreUtils.updateUser(userModel.value);
_navigateBasedOnAddress(userModel.value);
} catch (e) {
ShowToastDialog.showToast("${'signup_failed'.tr}: $e");
}
}
/// Construct UserModel
Future<UserModel> _buildUserModel(String uid) async {
final fcmToken = await NotificationService.getToken();
return UserModel(
id: uid,
firstName: firstNameController.value.text.trim(),
lastName: lastNameController.value.text.trim(),
email: emailController.value.text.trim().toLowerCase(),
phoneNumber: mobileController.value.text.trim(),
countryCode: countryCodeController.value.text.trim(),
fcmToken: fcmToken,
active: true,
createdAt: Timestamp.now(),
role: Constant.userRoleCustomer,
);
}
/// Handle Referral Logic
Future<void> _handleReferral(String userId) async {
final referralCode = referralController.value.text.trim();
final referralBy = referralCode.isNotEmpty ? (await FireStoreUtils.getReferralUserByCode(referralCode))?.id ?? '' : '';
final referral = ReferralModel(id: userId, referralBy: referralBy, referralCode: Constant.getReferralCode());
await FireStoreUtils.referralAdd(referral);
}
/// Navigate Based on Shipping Address
void _navigateBasedOnAddress(UserModel user) {
if (user.shippingAddress?.isNotEmpty == true) {
final defaultAddress = user.shippingAddress!.firstWhere((e) => e.isDefault == true, orElse: () => user.shippingAddress!.first);
/// Save the default address to global constant
Constant.selectedLocation = defaultAddress;
Get.offAll(() => const ServiceListScreen());
} else {
Get.offAll(() => const LocationPermissionScreen());
}
}
}

View File

@@ -0,0 +1,67 @@
import 'dart:async';
import 'dart:developer';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/screen_ui/maintenance_mode_screen/maintenance_mode_screen.dart';
import 'package:customer/screen_ui/service_home_screen/service_list_screen.dart';
import 'package:customer/utils/notification_service.dart';
import 'package:customer/utils/preferences.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
import '../screen_ui/auth_screens/login_screen.dart';
import '../screen_ui/location_enable_screens/location_permission_screen.dart';
import '../screen_ui/on_boarding_screen/on_boarding_screen.dart';
import '../service/fire_store_utils.dart';
class SplashController extends GetxController {
@override
void onInit() {
Timer(const Duration(seconds: 3), () => redirectScreen());
super.onInit();
}
Future<void> redirectScreen() async {
if (Constant.isMaintenanceModeForCustomer == true) {
Get.offAll(const MaintenanceModeScreen());
return;
}
if (Preferences.getBoolean(Preferences.isFinishOnBoardingKey) == false) {
Get.offAll(const OnboardingScreen());
} else {
bool isLogin = await FireStoreUtils.isLogin();
if (isLogin == true) {
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) async {
if (value != null) {
UserModel userModel = value;
log(userModel.toJson().toString());
if (userModel.role == Constant.userRoleCustomer) {
if (userModel.active == true) {
userModel.fcmToken = await NotificationService.getToken();
await FireStoreUtils.updateUser(userModel);
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
if (userModel.shippingAddress!.where((element) => element.isDefault == true).isNotEmpty) {
Constant.selectedLocation = userModel.shippingAddress!.where((element) => element.isDefault == true).single;
} else {
Constant.selectedLocation = userModel.shippingAddress!.first;
}
Get.offAll(const ServiceListScreen());
} else {
Get.offAll(const LocationPermissionScreen());
}
} else {
await FirebaseAuth.instance.signOut();
Get.offAll(const LoginScreen());
}
} else {
await FirebaseAuth.instance.signOut();
Get.offAll(const LoginScreen());
}
}
});
} else {
await FirebaseAuth.instance.signOut();
Get.offAll(const LoginScreen());
}
}
}
}

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../utils/preferences.dart';
class ThemeController extends GetxController {
RxBool isDark = false.obs;
@override
void onInit() {
super.onInit();
loadTheme();
}
void loadTheme() {
// Use safe getBoolean from Preferences
isDark.value = Preferences.getBoolean(Preferences.themKey);
}
void toggleTheme() {
isDark.value = !isDark.value;
Preferences.setBoolean(Preferences.themKey, isDark.value);
}
ThemeMode get themeMode => isDark.value ? ThemeMode.dark : ThemeMode.light;
}

View File

@@ -0,0 +1,31 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/models/vendor_category_model.dart';
import '../service/fire_store_utils.dart';
import 'package:get/get.dart';
class ViewAllCategoryController extends GetxController {
RxBool isLoading = true.obs;
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
@override
void onInit() {
// TODO: implement onInit
getCategoryData();
super.onInit();
}
Future<void> getCategoryData() async {
await FireStoreUtils.getVendorCategory().then((value) {
vendorCategoryModel.value = value;
});
if (Constant.restaurantList != null) {
List<String> usedCategoryIds = Constant.restaurantList!.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
}
isLoading.value = false;
}
}

View File

@@ -0,0 +1,83 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/controllers/on_demand_home_controller.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import '../models/favorite_ondemand_service_model.dart';
import '../models/provider_serivce_model.dart';
import '../service/fire_store_utils.dart';
class ViewAllPopularServiceController extends GetxController {
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
RxList<ProviderServiceModel> allProviderList = <ProviderServiceModel>[].obs;
RxBool isLoading = true.obs;
Rx<OnDemandHomeController> onDemandHomeController = Get.find<OnDemandHomeController>().obs;
final OnDemandHomeController onDemandController = Get.find<OnDemandHomeController>();
Rx<TextEditingController> searchTextFiledController = TextEditingController().obs;
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
@override
void onInit() {
super.onInit();
getData();
}
Future<void> getData() async {
isLoading.value = true;
await FireStoreUtils.getProviderFuture()
.then((providerServiceList) {
Set<String?> uniqueAuthorIds = providerServiceList.map((service) => service.author).toSet();
List<String?> listOfUniqueProviders = uniqueAuthorIds.toList();
List<ProviderServiceModel> filteredProviders = [];
for (var provider in listOfUniqueProviders) {
List<ProviderServiceModel> filteredList = providerServiceList.where((service) => service.author == provider).toList();
filteredList.sort((a, b) => a.createdAt!.compareTo(b.createdAt!));
for (int index = 0; index < filteredList.length; index++) {
final service = filteredList[index];
if (Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel?.adminCommision?.isEnabled == true) {
if (service.subscriptionPlan?.itemLimit == "-1") {
filteredProviders.add(service);
} else {
if (index < int.parse(service.subscriptionPlan?.itemLimit ?? '0')) {
filteredProviders.add(service);
}
}
} else {
filteredProviders.add(service);
}
}
}
allProviderList.value = filteredProviders;
providerList.value = filteredProviders;
isLoading.value = false;
})
.catchError((e) {
print("Provider error: $e");
isLoading.value = false;
});
if (Constant.userModel != null) {
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((value) {
lstFav.value = value;
});
}
isLoading.value = false;
}
void getFilterData(String value) {
if (value.isNotEmpty) {
providerList.value = allProviderList.where((e) => e.title!.toLowerCase().contains(value.toLowerCase()) || e.title!.startsWith(value)).toList();
} else {
providerList.assignAll(allProviderList);
}
}
}

View File

@@ -0,0 +1,65 @@
import 'package:customer/constant/constant.dart';
import 'package:customer/controllers/on_demand_home_controller.dart';
import 'package:get/get.dart';
import '../models/provider_serivce_model.dart';
import '../service/fire_store_utils.dart';
class ViewCategoryServiceController extends GetxController {
RxBool isLoading = true.obs;
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
RxString categoryId = "".obs, categoryTitle = "".obs;
Rx<OnDemandHomeController> onDemandHomeController = Get.find<OnDemandHomeController>().obs;
@override
void onInit() {
super.onInit();
final args = Get.arguments as Map<String, dynamic>;
categoryId.value = args['categoryId'] ?? "";
categoryTitle.value = args['categoryTitle'] ?? "";
getData();
}
Future<void> getData() async {
providerList.clear();
isLoading.value = true;
List<ProviderServiceModel> providerServiceList = await FireStoreUtils.getProviderFuture(categoryId: categoryId.value);
List<String?> uniqueAuthId = providerServiceList.map((service) => service.author).toList();
List<String?> uniqueServiceId = providerServiceList.map((service) => service.id).toList();
List<ProviderServiceModel> filterByItemLimit = <ProviderServiceModel>[];
List<String?> uniqueId = <String>[];
if ((Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel!.adminCommision?.isEnabled == true)) {
for (var authUser in uniqueAuthId) {
List<ProviderServiceModel> listofAllServiceByAuth = await FireStoreUtils.getAllProviderServiceByAuthorId(authUser!);
for (int i = 0; i < listofAllServiceByAuth.length; i++) {
if (listofAllServiceByAuth[i].subscriptionPlan?.itemLimit != null &&
(i < int.parse(listofAllServiceByAuth[i].subscriptionPlan?.itemLimit ?? '0') || listofAllServiceByAuth[i].subscriptionPlan?.itemLimit == '-1')) {
if (uniqueServiceId.contains(listofAllServiceByAuth[i].id)) {
filterByItemLimit.add(listofAllServiceByAuth[i]);
}
}
}
for (var service in filterByItemLimit) {
for (var unique in uniqueServiceId) {
if (service.id == unique && !uniqueId.contains(service.id) && service.subscriptionTotalOrders != '0') {
uniqueId.add(service.id);
providerList.add(service);
}
}
}
}
} else {
providerList.addAll(providerServiceList);
}
isLoading.value = false;
}
}

View File

@@ -0,0 +1,601 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as maths;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constant/constant.dart';
import 'package:customer/models/payment_model/flutter_wave_model.dart';
import 'package:customer/models/payment_model/mercado_pago_model.dart';
import 'package:customer/models/payment_model/mid_trans.dart';
import 'package:customer/models/payment_model/orange_money.dart';
import 'package:customer/models/payment_model/pay_fast_model.dart';
import 'package:customer/models/payment_model/pay_stack_model.dart';
import 'package:customer/models/payment_model/paypal_model.dart';
import 'package:customer/models/payment_model/razorpay_model.dart';
import 'package:customer/models/payment_model/stripe_model.dart';
import 'package:customer/models/payment_model/xendit.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/wallet_transaction_model.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:flutter_paypal/flutter_paypal.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../payment/MercadoPagoScreen.dart';
import '../payment/PayFastScreen.dart';
import '../payment/midtrans_screen.dart';
import '../payment/orangePayScreen.dart';
import '../payment/paystack/pay_stack_screen.dart';
import '../payment/paystack/pay_stack_url_model.dart';
import '../payment/paystack/paystack_url_genrater.dart';
import '../payment/stripe_failed_model.dart';
import '../payment/xenditModel.dart';
import '../payment/xenditScreen.dart';
import '../service/fire_store_utils.dart';
import 'package:customer/utils/preferences.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
import '../themes/show_toast_dialog.dart';
class WalletController extends GetxController {
RxBool isLoading = true.obs;
Rx<TextEditingController> topUpAmountController = TextEditingController().obs;
RxList<WalletTransactionModel> walletTransactionList = <WalletTransactionModel>[].obs;
Rx<UserModel> userModel = UserModel().obs;
RxString selectedPaymentMethod = "".obs;
@override
void onInit() {
// TODO: implement onInit
getPaymentSettings();
getWalletTransaction();
super.onInit();
}
Rx<PayFastModel> payFastModel = PayFastModel().obs;
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
Rx<PayPalModel> payPalModel = PayPalModel().obs;
Rx<StripeModel> stripeModel = StripeModel().obs;
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
Rx<PayStackModel> payStackModel = PayStackModel().obs;
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
Rx<MidTrans> midTransModel = MidTrans().obs;
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
Rx<Xendit> xenditModel = Xendit().obs;
Future<void> getPaymentSettings() async {
await FireStoreUtils.getPaymentSettingsData().then((value) {
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
orangeMoneyModel.value = OrangeMoney.fromJson(json.decode(Preferences.getString(Preferences.orangeMoneySettings)));
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
Stripe.merchantIdentifier = 'GoRide';
Stripe.instance.applySettings();
setRef();
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
});
}
Future<void> getWalletTransaction() async {
if (Constant.userModel != null) {
await FireStoreUtils.getWalletTransaction().then((value) {
if (value != null) {
walletTransactionList.value = value;
}
});
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
if (value != null) {
userModel.value = value;
}
});
}
isLoading.value = false;
}
Future<void> walletTopUp() async {
WalletTransactionModel transactionModel = WalletTransactionModel(
id: Constant.getUuid(),
amount: double.parse(topUpAmountController.value.text),
date: Timestamp.now(),
paymentMethod: selectedPaymentMethod.value,
transactionUser: "user",
userId: FireStoreUtils.getCurrentUid(),
isTopup: true,
note: "Wallet Top-up",
paymentStatus: "success",
);
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
if (value == true) {
await FireStoreUtils.updateUserWallet(amount: topUpAmountController.value.text, userId: FireStoreUtils.getCurrentUid()).then((value) {
getWalletTransaction();
Get.back();
});
}
});
ShowToastDialog.showToast("Amount Top-up successfully".tr);
}
// Strip
Future<void> stripeMakePayment({required String amount}) async {
log(double.parse(amount).toStringAsFixed(0));
try {
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
log("stripe Responce====>$paymentIntentData");
if (paymentIntentData!.containsKey("error")) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
} else {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['client_secret'],
allowsDelayedPaymentMethods: false,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
customFlow: true,
style: ThemeMode.system,
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
merchantDisplayName: 'GoRide',
),
);
displayStripePaymentSheet(amount: amount);
}
} catch (e, s) {
log("$e \n$s");
ShowToastDialog.showToast("exception:$e \n$s");
}
}
Future<void> displayStripePaymentSheet({required String amount}) async {
try {
await Stripe.instance.presentPaymentSheet().then((value) {
ShowToastDialog.showToast("Payment successfully".tr);
walletTopUp();
});
} on StripeException catch (e) {
var lo1 = jsonEncode(e);
var lo2 = jsonDecode(lo1);
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
ShowToastDialog.showToast(lom.error.message);
} catch (e) {
ShowToastDialog.showToast(e.toString());
}
}
Future createStripeIntent({required String amount}) async {
try {
Map<String, dynamic> body = {
'amount': ((double.parse(amount) * 100).round()).toString(),
'currency': "USD",
'payment_method_types[]': 'card',
"description": "Strip Payment",
"shipping[name]": userModel.value.fullName(),
"shipping[address][line1]": "510 Townsend St",
"shipping[address][postal_code]": "98140",
"shipping[address][city]": "San Francisco",
"shipping[address][state]": "CA",
"shipping[address][country]": "US",
};
var stripeSecret = stripeModel.value.stripeSecret;
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
);
return jsonDecode(response.body);
} catch (e) {
log(e.toString());
}
}
//mercadoo
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"items": [
{
"title": "Test",
"description": "Test Payment",
"quantity": 1,
"currency_id": "BRL", // or your preferred currency
"unit_price": double.parse(amount),
},
],
"payer": {"email": userModel.value.email},
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
"auto_return": "approved", // Automatically return after payment is approved
});
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something want wrong please contact administrator".tr);
print('Error creating preference: ${response.body}');
return null;
}
}
void paypalPaymentSheet(String amount, context) {
Navigator.of(context).push(
MaterialPageRoute(
builder:
(BuildContext context) => UsePaypal(
sandboxMode: payPalModel.value.isLive == true ? false : true,
clientId: payPalModel.value.paypalClient ?? '',
secretKey: payPalModel.value.paypalSecret ?? '',
returnURL: "com.parkme://paypalpay",
cancelURL: "com.parkme://paypalpay",
transactions: [
{
"amount": {
"total": amount,
"currency": "USD",
"details": {"subtotal": amount},
},
},
],
note: "Contact us for any questions on your order.",
onSuccess: (Map params) async {
walletTopUp();
ShowToastDialog.showToast("Payment Successful!!".tr);
},
onError: (error) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
onCancel: (params) {
Get.back();
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
},
),
),
);
}
///PayStack Payment Method
Future<void> payStackPayment(String totalAmount) async {
await PayStackURLGen.payStackURLGen(amount: (double.parse(totalAmount) * 100).toString(), currency: "ZAR", secretKey: payStackModel.value.secretKey.toString(), userModel: userModel.value).then((
value,
) async {
if (value != null) {
PayStackUrlModel payStackModel0 = value;
Get.to(
PayStackScreen(
secretKey: payStackModel.value.secretKey.toString(),
callBackUrl: payStackModel.value.callbackURL.toString(),
initialURl: payStackModel0.data.authorizationUrl,
amount: totalAmount,
reference: payStackModel0.data.reference,
),
)!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
}
});
}
//flutter wave Payment Method
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
final body = jsonEncode({
"tx_ref": _ref,
"amount": amount,
"currency": "NGN",
"redirect_url": "${Constant.globalUrl}payment/success",
"payment_options": "ussd, card, barter, payattitude",
"customer": {
"email": userModel.value.email.toString(),
"phonenumber": userModel.value.phoneNumber, // Add a real phone number
"name": userModel.value.fullName(), // Add a real customer name
},
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
});
final response = await http.post(url, headers: headers, body: body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
if (value) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
} else {
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
}
});
} else {
print('Payment initialization failed: ${response.body}');
return null;
}
}
String? _ref;
void setRef() {
maths.Random numRef = maths.Random();
int year = DateTime.now().year;
int refNumber = numRef.nextInt(20000);
if (Platform.isAndroid) {
_ref = "AndroidRef$year$refNumber";
} else if (Platform.isIOS) {
_ref = "IOSRef$year$refNumber";
}
}
// payFast
void payFastPayment({required BuildContext context, required String amount}) {
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: userModel.value).then((String? value) async {
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
if (isDone) {
Get.back();
ShowToastDialog.showToast("Payment successfully".tr);
walletTopUp();
} else {
Get.back();
ShowToastDialog.showToast("Payment Failed".tr);
}
});
}
///RazorPay payment function
final Razorpay razorPay = Razorpay();
void openCheckout({required amount, required orderId}) async {
var options = {
'key': razorPayModel.value.razorpayKey,
'amount': amount * 100,
'name': 'GoRide',
'order_id': orderId,
"currency": "INR",
'description': 'wallet Topup',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {'contact': userModel.value.phoneNumber, 'email': userModel.value.email},
'external': {
'wallets': ['paytm'],
},
};
try {
razorPay.open(options);
} catch (e) {
debugPrint('Error: $e');
}
}
void handlePaymentSuccess(PaymentSuccessResponse response) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
}
void handleExternalWaller(ExternalWalletResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Processing!! via".tr);
}
void handlePaymentError(PaymentFailureResponse response) {
Get.back();
ShowToastDialog.showToast("Payment Failed!!".tr);
}
//Midtrans payment
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
await createPaymentLink(amount: amount).then((url) {
ShowToastDialog.closeLoader();
if (url != '') {
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<String> createPaymentLink({required var amount}) async {
var ordersId = const Uuid().v1();
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
final response = await http.post(
url,
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
body: jsonEncode({
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
'usage_limit': 2,
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
}),
);
if (response.statusCode == 200 || response.statusCode == 201) {
final responseData = jsonDecode(response.body);
return responseData['payment_url'];
} else {
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
return '';
}
}
String generateBasicAuthHeader(String apiKey) {
String credentials = '$apiKey:';
String base64Encoded = base64Encode(utf8.encode(credentials));
return 'Basic $base64Encoded';
}
//Orangepay payment
static String accessToken = '';
static String payToken = '';
static String orderId = '';
static String amount = '';
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
reset();
var id = const Uuid().v4();
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
ShowToastDialog.closeLoader();
if (paymentURL.toString() != '') {
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
}
});
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
}
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
String apiUrl = 'https://api.orange.com/oauth/v3/token';
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
body: requestBody,
);
if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body);
accessToken = responseData['access_token'];
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
orderId = orderIdData;
amount = amountData;
String apiUrl = orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
Map<String, String> requestBody = {
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
"order_id": orderId,
"amount": amount,
"reference": 'Y-Note Test',
"lang": "en",
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
};
var response = await http.post(
Uri.parse(apiUrl),
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
body: json.encode(requestBody),
);
print(response.statusCode);
print(response.body);
// Handle the response
if (response.statusCode == 201) {
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData['message'] == 'OK') {
payToken = responseData['pay_token'];
return responseData['payment_url'];
} else {
return '';
}
} else {
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
return '';
}
}
static void reset() {
accessToken = '';
payToken = '';
orderId = '';
amount = '';
}
//XenditPayment
Future<void> xenditPayment(context, amount) async {
await createXenditInvoice(amount: amount).then((model) {
ShowToastDialog.closeLoader();
if (model.id != null) {
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
if (value == true) {
ShowToastDialog.showToast("Payment Successful!!".tr);
walletTopUp();
} else {
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
}
});
}
});
}
Future<XenditModel> createXenditInvoice({required var amount}) async {
const url = 'https://api.xendit.co/v2/invoices';
var headers = {
'Content-Type': 'application/json',
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
};
final body = jsonEncode({
'external_id': const Uuid().v1(),
'amount': amount,
'payer_email': 'customer@domain.com',
'description': 'Test - VA Successful invoice payment',
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
});
try {
final response = await http.post(Uri.parse(url), headers: headers, body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
return model;
} else {
return XenditModel();
}
} catch (e) {
return XenditModel();
}
}
}

71
lib/firebase_options.dart Normal file
View File

@@ -0,0 +1,71 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyALZhdy7Rw3jffipxsDvvz7_C_b4teVg1k',
appId: '1:893074789710:android:05002c15a64cf1e0c4ba1f',
messagingSenderId: '893074789710',
projectId: 'fondexuzb',
databaseURL: 'https://fondexuzb-default-rtdb.firebaseio.com',
storageBucket: 'fondexuzb.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyD6Khoz4y93GCj3mOPi2FoluDipplH1av0',
appId: '1:893074789710:ios:510ebf9e4ebed6a8c4ba1f',
messagingSenderId: '893074789710',
projectId: 'fondexuzb',
databaseURL: 'https://fondexuzb-default-rtdb.firebaseio.com',
storageBucket: 'fondexuzb.firebasestorage.app',
iosClientId: '893074789710-pv12m4nhe82a4ueg9sb2pgt42r0e5da3.apps.googleusercontent.com',
iosBundleId: 'com.emart.customer',
);
}

784
lib/lang/app_en.dart Normal file
View File

@@ -0,0 +1,784 @@
const Map<String, String> enUS = {
'Lets Get Started': 'Lets Get Started',
'Skip': 'Skip',
'Next': 'Next',
'Log in to explore your all in one vendor app favourites and shop effortlessly.': 'Log in to explore your all in one vendor app favourites and shop effortlessly.',
'Email Address*': 'Email Address*',
'jerome014@gmail.com': 'jerome014@gmail.com',
'Password*': 'Password*',
'Enter password': 'Enter password',
'Forgot Password': 'Forgot Password',
'Log in': 'Log in',
'or continue with': 'or continue with',
'Mobile number': 'Mobile number',
'with Google': 'with Google',
'with Apple': 'with Apple',
"Didn't have an account?": "Didn't have an account?",
'Sign up': 'Sign up',
'Please enter a valid email address': 'Please enter a valid email address',
'Please enter your password': 'Please enter your password',
'Logging in...': 'Logging in...',
'This user is disabled. Please contact admin.': 'This user is disabled. Please contact admin.',
'This user does not exist in the customer app.': 'This user does not exist in the customer app.',
'No user found for that email.': 'No user found for that email.',
'Wrong password provided.': 'Wrong password provided.',
'Invalid email.': 'Invalid email.',
'Login failed. Please try again.': 'Login failed. Please try again.',
'please wait...': 'please wait...',
'Sign up to explore all our services and start shopping, riding, and more.': 'Sign up to explore all our services and start shopping, riding, and more.',
'First Name*': 'First Name*',
'Jerome': 'Jerome',
'KM': 'KM',
'Last Name*': 'Last Name*',
'Bell': 'Bell',
'Mobile Number*': 'Mobile Number*',
'Enter Mobile number': 'Enter Mobile number',
'Confirm Password*': 'Confirm Password*',
'Enter confirm password': 'Enter confirm password',
'Referral Code': 'Referral Code',
'Enter referral code': 'Enter referral code',
'Already have an account?': 'Already have an account?',
'Creating account...': 'Creating account...',
'signup_failed': 'Signup failed',
'Please enter first name': 'Please enter first name',
'Please enter last name': 'Please enter last name',
'Please enter a valid phone number': 'Please enter a valid phone number',
'Password must be at least 6 characters': 'Password must be at least 6 characters',
'Password and Confirm password do not match': 'Password and Confirm password do not match',
'Email already in use': 'Email already in use',
'Password is too weak': 'Password is too weak',
'Invalid email address': 'Invalid email address',
'something_went_wrong': 'Something went wrong',
'Enter your registered email to receive a reset link.': 'Enter your registered email to receive a reset link.',
'Send Link': 'Send Link',
'Remember Password?': 'Remember Password?',
'Please enter your email address.': 'Please enter your email address.',
'Please enter a valid email address.': 'Please enter a valid email address.',
"reset_password_link_sent": "Reset password link sent to @email",
'Use your mobile number to Log in easily and securely.': 'Use your mobile number to Log in easily and securely.',
'Send Code': 'Send Code',
'Email address': 'Email address',
'Please enter a valid 10-digit mobile number': 'Please enter a valid 10-digit mobile number',
'Sending OTP...': 'Sending OTP...',
'Invalid phone number': 'Invalid phone number',
'OTP verification failed': 'OTP verification failed',
'Something went wrong. Please try again.': 'Something went wrong. Please try again.',
'Enter the OTP sent to your mobile': 'Enter the OTP sent to your mobile',
'Resend OTP': 'Resend OTP',
'Verify': 'Verify',
'OTP sent': 'OTP sent',
'Enter valid 6-digit OTP': 'Enter valid 6-digit OTP',
'Verifying OTP...': 'Verifying OTP...',
'This user is disabled': 'This user is disabled',
'Invalid OTP or Verification Failed': 'Invalid OTP or Verification Failed',
'eMart': 'eMart',
'All Your Needs in One App!': 'All Your Needs in One App!',
'Explore Our Services': 'Explore Our Services',
'Alert!': 'Alert!',
'Alert': 'Alert',
'If you select this Section/Service, your previously added items will be removed from the cart.': 'If you select this Section/Service, your previously added items will be removed from the cart.',
'Cancel': 'Cancel',
'OK': 'OK',
'Home': 'Home',
'My Bookings': 'My Bookings',
'Favourites': 'Favourites',
'Orders': 'Orders',
'Profile': 'Profile',
'Wallet': 'Wallet',
'Service is unavailable at the selected address.': 'Service is unavailable at the selected address.',
'Pickup Location': 'Pickup Location',
'Destination Location': 'Destination Location',
'Continue': 'Continue',
'Please select source location': 'Please select source location',
'Please select destination location': 'Please select destination location',
'Select Your Vehicle Type': 'Select Your Vehicle Type',
"pay_amount": "Pay @amount",
'Please select a vehicle type first.': 'Please select a vehicle type first.',
'Select Payment Method': 'Select Payment Method',
'Preferred Payment': 'Preferred Payment',
'Other Payment Options': 'Other Payment Options',
'Please select a payment method': 'Please select a payment method',
'Insufficient wallet balance. Please select another payment method.': 'Insufficient wallet balance. Please select another payment method.',
'Promo code': 'Promo code',
'Promo Code': 'Promo Code',
'Apply promo code': 'Apply promo code',
'This offer not eligible for this booking': 'This offer not eligible for this booking',
'View All': 'View All',
'Write coupon Code': 'Write coupon Code',
'Redeem now': 'Redeem now',
'Please enter a coupon code': 'Please enter a coupon code',
'Coupon applied successfully': 'Coupon applied successfully',
'This coupon code has been expired': 'This coupon code has been expired',
'Invalid coupon code': 'Invalid coupon code',
'Order Summary': 'Order Summary',
'Subtotal': 'Subtotal',
'SubTotal': 'SubTotal',
'Discount': 'Discount',
'Order Total': 'Order Total',
'Confirm Booking': 'Confirm Booking',
'Waiting for driver....': 'Waiting for driver....',
'Cancel Ride': 'Cancel Ride',
'Ride cancelled successfully': 'Ride cancelled successfully',
'Failed to cancel ride': 'Failed to cancel ride',
'Otp :': 'Otp :',
'SOS': 'SOS',
'Please wait...': 'Please wait...',
'Your SOS request has been submitted to admin': 'Your SOS request has been submitted to admin',
'Your SOS request is already submitted': 'Your SOS request is already submitted',
'Pay Now': 'Pay Now',
'Something went wrong, please contact admin.': 'Something went wrong, please contact admin.',
'Please select payment method': 'Please select payment method',
'Driver at Pickup': 'Driver at Pickup',
'Driver Location': 'Driver Location',
'Payment method changed': 'Payment method changed',
'Payment successfully': 'Payment successfully',
'Payment Successful!!': 'Payment Successful!!',
'Payment UnSuccessful!!': 'Payment UnSuccessful!!',
'Payment Failed': 'Payment Failed',
'Payment Processing!! via': 'Payment Processing!! via',
'Payment Failed!!': 'Payment Failed!!',
'Coupon': 'Coupon',
'Coupon not found': 'Coupon not found',
'Tap To Apply': 'Tap To Apply',
'My Booking': 'My Booking',
'Login': 'Login',
'Where are you going for?': 'Where are you going for?',
'Ride': 'Ride',
'City rides, 24x7 availability': 'City rides, 24x7 availability',
'Intercity/Outstation': 'Intercity/Outstation',
'Long trips, prepaid options': 'Long trips, prepaid options',
'Every Ride. Every Driver. Verified.': 'Every Ride. Every Driver. Verified.',
'All drivers go through ID checks and background verification for your safety.': 'All drivers go through ID checks and background verification for your safety.',
'Ride Details': 'Ride Details',
'Order Id:': 'Order Id:',
'Booking Date:': 'Booking Date:',
'Ride & Fare Summary': 'Ride & Fare Summary',
'Add Review': 'Add Review',
'Complain': 'Complain',
'Distance': 'Distance',
'Duration': 'Duration',
'Update Review': 'Update Review',
'How is your trip?': 'How is your trip?',
'Your feedback will help us improve \n driving experience better': 'Your feedback will help us improve \n driving experience better',
'Rate for': 'Rate for',
'Type comment....': 'Type comment....',
'Please provide rating and comment': 'Please provide rating and comment',
'Submit in...': 'Submit in...',
'Title': 'Title',
'Save': 'Save',
'Type Description....': 'Type Description....',
'Order data not found': 'Order data not found',
'Failed to load complaint': 'Failed to load complaint',
'Please enter complaint title': 'Please enter complaint title',
'Please enter complaint description': 'Please enter complaint description',
'Your complaint has been submitted to admin': 'Your complaint has been submitted to admin',
'Your complaint is already submitted': 'Your complaint is already submitted',
'Something went wrong, please try again': 'Something went wrong, please try again',
'Popular Destinations': 'Popular Destinations',
'Ride History': 'Ride History',
'No order found': 'No order found',
'You do not have sufficient wallet balance': 'You do not have sufficient wallet balance',
"new_tab": "New",
"on_going_tab": "On Going",
"completed_tab": "Completed",
"cancelled_tab": "Cancelled",
'New': 'New',
'On Going': 'On Going',
'Completed': 'Completed',
'Cancelled': 'Cancelled',
'My Addresses': 'My Addresses',
'Allows users to view, manage, add, or edit delivery addresses': 'Allows users to view, manage, add, or edit delivery addresses',
'Address not found': 'Address not found',
'Default': 'Default',
'Add New Address': 'Add New Address',
'Edit Address': 'Edit Address',
'Add a New Address': 'Add a New Address',
'Enter your location details so we can deliver your orders quickly and accurately.': 'Enter your location details so we can deliver your orders quickly and accurately.',
'Set as Default Address': 'Set as Default Address',
'Choose Location': 'Choose Location',
'Flat/House/Floor/Building*': 'Flat/House/Floor/Building*',
'Area/Sector/Locality*': 'Area/Sector/Locality*',
'Nearby Landmark': 'Nearby Landmark',
'Save Address As': 'Save Address As',
'Enter address details': 'Enter address details',
'Enter area/locality': 'Enter area/locality',
'Add a landmark': 'Add a landmark',
'Save Address': 'Save Address',
'Please select Location': 'Please select Location',
'Please Enter Flat / House / Floor / Building': 'Please Enter Flat / House / Floor / Building',
'Please Enter Area / Sector / Locality': 'Please Enter Area / Sector / Locality',
'Enable Location for a Personalized Experience': 'Enable Location for a Personalized Experience',
'Allow location access to discover beauty stores and services near you.': 'Allow location access to discover beauty stores and services near you.',
'Use current location': 'Use current location',
'Set from map': 'Set from map',
'Enter Manually location': 'Enter Manually location',
'Search the store, item and more...': 'Search the store, item and more...',
'Category': 'Category',
'Highlights for you': 'Highlights for you',
'New Arrivals': 'New Arrivals',
'View All Arrivals': 'View All Arrivals',
'Top Brands': 'Top Brands',
'Brand': 'Brand',
'Style up with the latest fits, now at unbeatable prices.': 'Style up with the latest fits, now at unbeatable prices.',
'View All Products': 'View All Products',
'All Store': 'All Store',
'View All Stores': 'View All Stores',
'Could not launch': 'Could not launch',
'Highlights for you not found.': 'Highlights for you not found.',
'Item Not available': 'Item Not available',
'Service not available in this area': 'Service not available in this area',
'Out of stock': 'Out of stock',
'Variants': 'Variants',
'Addons': 'Addons',
'Delivery Type': 'Delivery Type',
'Instant Delivery': 'Instant Delivery',
'Standard': 'Standard',
'instant': 'instant',
'schedule': 'schedule',
'Schedule Time': 'Schedule Time',
'Your preferred time': 'Your preferred time',
'Offers & Benefits': 'Offers & Benefits',
'Apply Coupons': 'Apply Coupons',
'Bill Details': 'Bill Details',
'Item totals': 'Item totals',
'Delivery Fee': 'Delivery Fee',
'Free Delivery': 'Free Delivery',
'Coupon Discount': 'Coupon Discount',
'Special Discount': 'Special Discount',
'Delivery Tips': 'Delivery Tips',
'Remove': 'Remove',
'To Pay': 'To Pay',
'Thanks with a tip!': 'Thanks with a tip!',
'Around the clock, our delivery partners make it happen. Show gratitude with a tip..': 'Around the clock, our delivery partners make it happen. Show gratitude with a tip..',
'Other': 'Other',
'Remarks': 'Remarks',
'Write remarks for the store': 'Write remarks for the store',
'Cashback Offer': 'Cashback Offer',
'Cashback Name :': 'Cashback Name :',
'You will get': 'You will get',
'Pay Via': 'Pay Via',
'The total price must be greater than or equal to the coupon discount value for the code to apply. Please review your cart total.':
'The total price must be greater than or equal to the coupon discount value for the code to apply. Please review your cart total.',
'The total price must be greater than or equal to the special discount value for the code to apply. Please review your cart total.':
'The total price must be greater than or equal to the special discount value for the code to apply. Please review your cart total.',
'Tips Amount': 'Tips Amount',
'Enter Tips Amount': 'Enter Tips Amount',
'Add': 'Add',
'Please enter tips Amount': 'Please enter tips Amount',
"You don't have sufficient wallet balance to place order": "You don't have sufficient wallet balance to place order",
'This vendor has reached their maximum order capacity. Please select a different vendor or try again later.':
'This vendor has reached their maximum order capacity. Please select a different vendor or try again later.',
'Coupon Code': 'Coupon Code',
'Enter coupon code': 'Enter coupon code',
'Invalid Coupon': 'Invalid Coupon',
'Apply': 'Apply',
'Coupon code not applied': 'Coupon code not applied',
'Order Placed': 'Order Placed',
'Hang tight — your items are being delivered quickly and safely!': 'Hang tight — your items are being delivered quickly and safely!',
'Order ID': 'Order ID',
'Placing your order': 'Placing your order',
'Take a moment to review your order before proceeding to checkout.': 'Take a moment to review your order before proceeding to checkout.',
'Delivery Address': 'Delivery Address',
'Track Order': 'Track Order',
'Payment Option': 'Payment Option',
'Cashback Offers': 'Cashback Offers',
'Min spent': 'Min spent',
'Maximum cashback up to': 'Maximum cashback up to',
'Valid till': 'Valid till',
'Change Language': 'Change Language',
'Select your preferred language for a personalized app experience.': 'Select your preferred language for a personalized app experience.',
'No Conversion found': 'No Conversion found',
'Type message here....': 'Type message here....',
'Send Media': 'Send Media',
'Choose image from gallery': 'Choose image from gallery',
'Choose video from gallery': 'Choose video from gallery',
'Take a picture': 'Take a picture',
'sent a message': 'sent a message',
'Sent a video': 'Sent a video',
'Sent a audio': 'Sent a audio',
'Driver Inbox': 'Driver Inbox',
'Store Inbox': 'Store Inbox',
'Dine in Bookings': 'Dine in Bookings',
'Order': 'Order',
'Peoples': 'Peoples',
'View in Map': 'View in Map',
'Call Now': 'Call Now',
'Booking Details': 'Booking Details',
'Name': 'Name',
'Phone number': 'Phone number',
'Date and Time': 'Date and Time',
'Guest': 'Guest',
'Upcoming': 'Upcoming',
'History': 'History',
'Upcoming Booking not found.': 'Upcoming Booking not found.',
'History not found.': 'History not found.',
'Guest Number': 'Guest Number',
'Book Table': 'Book Table',
'Numbers of Guests': 'Numbers of Guests',
'When are you visiting?': 'When are you visiting?',
'Today': 'Today',
'Tomorrow': 'Tomorrow',
'Select time slot and scroll to see offers': 'Select time slot and scroll to see offers',
'Special Occasion': 'Special Occasion',
'Clear': 'Clear',
'Is this your first visit?': 'Is this your first visit?',
'Personal Details': 'Personal Details',
'Additional Requests': 'Additional Requests',
'Add message here....': 'Add message here....',
'Book Now': 'Book Now',
'Dine-In Request submitted successfully.': 'Dine-In Request submitted successfully.',
"Birthday": "Birthday",
"Anniversary": "Anniversary",
'Ratings': 'Ratings',
'Open': 'Open',
'Close': 'Close',
'View Timing': 'View Timing',
'View Timings': 'View Timings',
'Also applicable on food delivery': 'Also applicable on food delivery',
'Please log in to the application. You are not logged in.': 'Please log in to the application. You are not logged in.',
'Table Booking': 'Table Booking',
'Quick Conformations': 'Quick Conformations',
'Available food delivery': 'Available food delivery',
'in 30-45 mins.': 'in 30-45 mins.',
'Menu': 'Menu',
'Location, Timing & Costs': 'Location, Timing & Costs',
'View on Map': 'View on Map',
'Timing': 'Timing',
'To': 'To',
'Cost for Two': 'Cost for Two',
'for two': 'for two',
'(approx)': '(approx)',
'Cuisines': 'Cuisines',
'Dine-In Reservations': 'Dine-In Reservations',
'Book a table at your favorite restaurant and enjoy a delightful dining experience.': 'Book a table at your favorite restaurant and enjoy a delightful dining experience.',
'No Store Found in Your Area': 'No Store Found in Your Area',
'Currently, there are no available store in your zone. Try changing your location to find nearby options.':
'Currently, there are no available store in your zone. Try changing your location to find nearby options.',
'Change Zone': 'Change Zone',
'Explore the Categories': 'Explore the Categories',
'View all': 'View all',
'Popular Stores': 'Popular Stores',
'All Stores': 'All Stores',
'Categories': 'Categories',
'Profile Information': 'Profile Information',
'View and update your personal details, contact information, and preferences.': 'View and update your personal details, contact information, and preferences.',
'First Name': 'First Name',
'Last Name': 'Last Name',
'Email': 'Email',
'Phone Number': 'Phone Number',
'Save Details': 'Save Details',
'camera': 'camera',
'gallery': 'gallery',
"failed_to_pick": "Failed to pick image",
'Your Favourites, All in One Place': 'Your Favourites, All in One Place',
'Please Log In to Continue': 'Please Log In to Continue',
"Youre not logged in. Please sign in to access your account and explore all features.": "Youre not logged in. Please sign in to access your account and explore all features.",
'Favourite Store': 'Favourite Store',
'Favourite Item': 'Favourite Item',
'Favourite Store not found.': 'Favourite Store not found.',
'Favourite Item not found.': 'Favourite Item not found.',
'error': 'error',
'Non Veg.': 'Non Veg.',
'Pure veg.': 'Pure veg.',
'Amount': 'Amount',
'No worries!! Well send you reset instructions': 'No worries!! Well send you reset instructions',
'Email Address': 'Email Address',
'Enter email address': 'Enter email address',
'Please enter valid email': 'Please enter valid email',
'Customize Gift Card': 'Customize Gift Card',
'Choose an amount': 'Choose an amount',
'Enter gift card amount': 'Enter gift card amount',
'Add Message (Optional)': 'Add Message (Optional)',
'Please enter Amount': 'Please enter Amount',
'Enter Amount': 'Enter Amount',
'Complete payment and share this e-gift card with loved ones using any app': 'Complete payment and share this e-gift card with loved ones using any app',
'Sub Total': 'Sub Total',
'Grand Total': 'Grand Total',
'Gift Card expire': 'Gift Card expire',
'days after purchase': 'days after purchase',
"You don't have sufficient wallet balance to purchase gift card": "You don't have sufficient wallet balance to purchase gift card",
'Gift card Purchases successfully': 'Gift card Purchases successfully',
'Purchased Gift card not found': 'Purchased Gift card not found',
'Gift Code': 'Gift Code',
'Gift Pin': 'Gift Pin',
'Share': 'Share',
'Redeemed': 'Redeemed',
'Not Redeem': 'Not Redeem',
'Gift Code :': 'Gift Code :',
'Gift Pin :': 'Gift Pin :',
'Price :': 'Price :',
'Expire Date :': 'Expire Date :',
'Message': 'Message',
'Redeem Gift Card': 'Redeem Gift Card',
'Enter your gift card code to enjoy discounts and special offers on your orders.': 'Enter your gift card code to enjoy discounts and special offers on your orders.',
'Enter gift code': 'Enter gift code',
'Enter gift pin': 'Enter gift pin',
'Redeem': 'Redeem',
'Please Enter Gift Code': 'Please Enter Gift Code',
'Please Enter Gift Pin': 'Please Enter Gift Pin',
'Gift voucher already redeemed': 'Gift voucher already redeemed',
'Gift Pin Invalid': 'Gift Pin Invalid',
'Gift Voucher expire': 'Gift Voucher expire',
'Voucher redeem successfully': 'Voucher redeem successfully',
'Invalid Gift Code': 'Invalid Gift Code',
'No Restaurant found': 'No Restaurant found',
"% off": "% OFF",
" off": " OFF",
'Off': 'Off',
'Search the restaurant, food and more...': 'Search the restaurant, food and more...',
'Largest Discounts': 'Largest Discounts',
'Delivery': 'Delivery',
'TakeAway': 'TakeAway',
'Do you really want to change the delivery option? Your cart will be empty.': 'Do you really want to change the delivery option? Your cart will be empty.',
'Ok': 'Ok',
'Upto': 'Upto',
"Error": "Error",
'Search the dish, foo and more...': 'Search the dish, foo and more...',
'See all': 'See all',
'Our Categories': 'Our Categories',
'Best Servings Food': 'Best Servings Food',
'Large Discounts': 'Large Discounts',
'Discounts Restaurants': 'Discounts Restaurants',
'Save Upto 50% Off': 'Save Upto 50% Off',
'% OFF': '% OFF',
'OFF': 'OFF',
'Stories': 'Stories',
'Best Food Stories Ever': 'Best Food Stories Ever',
'Best Restaurants': 'Best Restaurants',
'Live Tracking': 'Live Tracking',
'Order Details': 'Order Details',
'Order Delivered.': 'Order Delivered.',
'Your Order has been Preparing and assign to the driver': 'Your Order has been Preparing and assign to the driver',
'Preparation Time': 'Preparation Time',
'Your Order': 'Your Order',
'Rate us': 'Rate us',
'Schedule': 'Schedule',
'Payment Method': 'Payment Method',
'Reorder': 'Reorder',
'Item Added In a cart': 'Item Added In a cart',
'Youre not logged in. Please sign in to access your account and explore all features': 'Youre not logged in. Please sign in to access your account and explore all features',
'My Order': 'My Order',
'Keep track your delivered, In Progress and Rejected item all in just one place.': 'Keep track your delivered, In Progress and Rejected item all in just one place.',
'All': 'All',
'In Progress': 'In Progress',
'Delivered': 'Delivered',
'Rejected': 'Rejected',
'Order Not Found': 'Order Not Found',
'View Details': 'View Details',
'My Profile': 'My Profile',
'Manage your personal information, preferences, and settings all in one place.': 'Manage your personal information, preferences, and settings all in one place.',
'General Information': 'General Information',
'Dine-In': 'Dine-In',
'Gift Card': 'Gift Card',
'Bookings Information': 'Bookings Information',
'Dine-In Booking': 'Dine-In Booking',
'Preferences': 'Preferences',
'Dark Mode': 'Dark Mode',
'Social': 'Social',
'Refer a Friend': 'Refer a Friend',
'Share app': 'Share app',
'Check out Foodie, your ultimate food delivery application!': 'Check out Foodie, your ultimate food delivery application!',
'Google Play:': 'Google Play:',
'App Store:': 'App Store:',
'Look what I made!': 'Look what I made!',
'Rate the app': 'Rate the app',
'Communication': 'Communication',
'Provider Inbox': 'Provider Inbox',
'Worker Inbox': 'Worker Inbox',
'Top up Wallet': 'Top up Wallet',
'Legal': 'Legal',
'Terms & Conditions': 'Terms & Conditions',
'Privacy Policy': 'Privacy Policy',
'Terms and Conditions': 'Terms and Conditions',
'Log out': 'Log out',
'Are you sure you want to log out? You will need to enter your credentials to log back in.': 'Are you sure you want to log out? You will need to enter your credentials to log back in.',
'Delete Account': 'Delete Account',
'Are you sure you want to delete your account? This action is irreversible and will permanently remove all your data.':
'Are you sure you want to delete your account? This action is irreversible and will permanently remove all your data.',
'Delete': 'Delete',
'Account deleted successfully': 'Account deleted successfully',
'Contact Administrator': 'Contact Administrator',
'V :': 'V :',
'Cashbacks': 'Cashbacks',
'Rate the item': 'Rate the item',
'Choose a image and upload here': 'Choose a image and upload here',
'JPEG, PNG': 'JPEG, PNG',
'Brows Image': 'Brows Image',
'Type comment': 'Type comment',
'Submit Review': 'Submit Review',
'Please Select': 'Please Select',
'Camera': 'Camera',
'Gallery': 'Gallery',
'Failed to pick image:': 'Failed to pick image:',
'Refer your friend and earn': 'Refer your friend and earn',
'Invite Friends & Businesses': 'Invite Friends & Businesses',
'Invite your friends to sign up with Foodie using your code, and youll earn': 'Invite your friends to sign up with Foodie using your code, and youll earn',
'after their Success the first order!': 'after their Success the first order!',
'Copied': 'Copied',
'or': 'or',
'Share Code': 'Share Code',
'Hey there, thanks for choosing Foodie. Hope you love our product. If you do, share it with your friends using code':
'Hey there, thanks for choosing Foodie. Hope you love our product. If you do, share it with your friends using code',
'and get': 'and get',
'when order completed': 'when order completed',
'items': 'items',
'View Cart': 'View Cart',
'Timing is not added by store': 'Timing is not added by store',
'Also applicable on table booking': 'Also applicable on table booking',
'Additional Offers': 'Additional Offers',
'Search the item and more...': 'Search the item and more...',
'Veg': 'Veg',
'Non Veg': 'Non Veg',
'Info': 'Info',
"Product Information's": "Product Information's",
'Gram': 'Gram',
'Calories': 'Calories',
'Proteins': 'Proteins',
'Fats': 'Fats',
'Specification': 'Specification',
'Back': 'Back',
'Required • Select any 1 option': 'Required • Select any 1 option',
'Add item': 'Add item',
'Reviews': 'Reviews',
'reviews': 'reviews',
'No Review found': 'No Review found',
'Scan QR Code': 'Scan QR Code',
'Store is not available': 'Store is not available',
'km': 'km',
"Change": "Change",
'Picked from Map': 'Picked from Map',
'Allows users to view, manage, add, or edit delivery addresses.': 'Allows users to view, manage, add, or edit delivery addresses.',
"We'll be back soon!": "We'll be back soon!",
"Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!":
"Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!",
'cashback after completing the order.': 'cashback after completing the order.',
'Please enter coupon code': 'Please enter coupon code',
'Pay': 'Pay',
'after their Success the first order! 💸🍔': 'after their Success the first order! 💸🍔',
'Find your favorite products and nearby stores': 'Find your favorite products and nearby stores',
'Search Item & Store': 'Search Item & Store',
'Search the store and item': 'Search the store and item',
'Store': 'Store',
'Select Top up Options': 'Select Top up Options',
'Top-up': 'Top-up',
'Please Enter minimum amount of': 'Please Enter minimum amount of',
'My Wallet': 'My Wallet',
'Keep track of your balance, transactions, and payment methods all in one place.': 'Keep track of your balance, transactions, and payment methods all in one place.',
'Top up': 'Top up',
'Transaction not found': 'Transaction not found',
'Order details not available': 'Order details not available',
'Favourite Services': 'Favourite Services',
'Favourite Service not found.': 'Favourite Service not found.',
'hr': 'hr',
'Booking History': 'Booking History',
'No ride found': 'No ride found',
'OTP :': 'OTP :',
'Date & Time': 'Date & Time',
'Provider': 'Provider',
'Start Time': 'Start Time',
'End Time': 'End Time',
'Worker': 'Worker',
'Book Service': 'Book Service',
'Services': 'Services',
'Address': 'Address',
'Description': 'Description',
'Enter Description': 'Enter Description',
'Booking Date & Slot': 'Booking Date & Slot',
'Choose Date and Time': 'Choose Date and Time',
'Price Detail': 'Price Detail',
'Confirm': 'Confirm',
'% Off': '% Off',
'valid till ': 'valid till ',
'Redeem Your Coupons': 'Redeem Your Coupons',
'Voucher or Coupon code': 'Voucher or Coupon code',
'REDEEM NOW': 'REDEEM NOW',
'Applied coupon not valid.': 'Applied coupon not valid.',
'Price': 'Price',
'Total Amount': 'Total Amount',
'Explore services': 'Explore services',
'Explore services tailored for you—quick, easy, and personalized.': 'Explore services tailored for you—quick, easy, and personalized.',
'No Categories': 'No Categories',
'About': 'About',
'Review': 'Review',
'No Image Found': 'No Image Found',
'No review Found': 'No review Found',
'Service Timing': 'Service Timing',
'Start Time : ': 'Start Time : ',
'End Time : ': 'End Time : ',
'Service Days': 'Service Days',
'No Service Found': 'No Service Found',
'All Services': 'All Services',
'Search Service': 'Search Service',
'No Services Found': 'No Services Found',
'Wallet balance is 0. Please recharge wallet.': 'Wallet balance is 0. Please recharge wallet.',
'Insufficient wallet balance. Please add funds.': 'Insufficient wallet balance. Please add funds.',
'Cancel Reason': 'Cancel Reason',
'Booking ID': 'Booking ID',
'Booking ID Copied': 'Booking ID Copied',
'Booking Address :': 'Booking Address :',
'Date:': 'Date:',
'Time:': 'Time:',
'About Worker': 'About Worker',
'Call': 'Call',
'Chat': 'Chat',
'About provider': 'About provider',
'Total Extra Charges : ': 'Total Extra Charges : ',
'Extra charge Notes : ': 'Extra charge Notes : ',
'New Date : ': 'New Date : ',
'Cancel Booking': 'Cancel Booking',
'Pay Extra Amount': 'Pay Extra Amount',
'Please give reason for canceling this Booking': 'Please give reason for canceling this Booking',
'Specify your reason here': 'Specify your reason here',
'Please enter reason': 'Please enter reason',
'Most Popular services': 'Most Popular services',
'"Total Amount': '"Total Amount',
'Book Your Document Delivery': 'Book Your Document Delivery',
'Schedule a secure and timely pickup & delivery': 'Schedule a secure and timely pickup & delivery',
'Sender Information': 'Sender Information',
'Receiver Information': 'Receiver Information',
'Select delivery type': 'Select delivery type',
'As soon as possible': 'As soon as possible',
'Scheduled': 'Scheduled',
'When to pickup at this address': 'When to pickup at this address',
'Upload parcel image': 'Upload parcel image',
'Upload Parcel Image': 'Upload Parcel Image',
'Supported: .jpg, .jpeg, .png': 'Supported: .jpg, .jpeg, .png',
'Max size 1MB': 'Max size 1MB',
'Browse Image': 'Browse Image',
'Your Location': 'Your Location',
'Select parcel Weight': 'Select parcel Weight',
'Normal': 'Normal',
'Notes (Optional)': 'Notes (Optional)',
'What are you sending?': 'What are you sending?',
'Parcel History': 'Parcel History',
'No orders found': 'No orders found',
'Order Date:': 'Order Date:',
'Pickup Address (Sender):': 'Pickup Address (Sender):',
'Delivery Address (Receiver):': 'Delivery Address (Receiver):',
'Your Order Has Been Placed!': 'Your Order Has Been Placed!',
'Weve received your parcel booking and its now being processed. You can track its status in real time.':
'Weve received your parcel booking and its now being processed. You can track its status in real time.',
'Track Your Order': 'Track Your Order',
'Order Confirmation': 'Order Confirmation',
'Weight': 'Weight',
'Rate': 'Rate',
'Coupons': 'Coupons',
'Write coupon code': 'Write coupon code',
'Payment by': 'Payment by',
'Sender': 'Sender',
'Receiver': 'Receiver',
'Insufficient wallet balance': 'Insufficient wallet balance',
'Your parcel is on the way. Track it in real time below.': 'Your parcel is on the way. Track it in real time below.',
'Schedule Pickup time:': 'Schedule Pickup time:',
'Parcel Type:': 'Parcel Type:',
'About Driver': 'About Driver',
'Cancel Parcel': 'Cancel Parcel',
'Parcel Status Timeline': 'Parcel Status Timeline',
'No status updates yet': 'No status updates yet',
'Rental History': 'Rental History',
'Vehicle Type :': 'Vehicle Type :',
'Package info :': 'Package info :',
'Confirm Rent a Car': 'Confirm Rent a Car',
'Your Preference': 'Your Preference',
'Your current location': 'Your current location',
'Please login to continue': 'Please login to continue',
'Please select a vehicle type': 'Please select a vehicle type',
'No preference available for the selected vehicle type': 'No preference available for the selected vehicle type',
'Select Preferences': 'Select Preferences',
'Booking Id :': 'Booking Id :',
'Booking ID copied to clipboard': 'Booking ID copied to clipboard',
'Rental Details': 'Rental Details',
'Rental Package': 'Rental Package',
'Rental Package Price': 'Rental Package Price',
'Including': 'Including',
'Including Hours': 'Including Hours',
'Hr': 'Hr',
'Extra': 'Extra',
'Extra Minutes': 'Extra Minutes',
'You are not able to pay now until driver adds kilometer': 'You are not able to pay now until driver adds kilometer',
'OnDemand Service successfully booked': 'OnDemand Service successfully booked',
'Booking Extra charge debited': 'Booking Extra charge debited',
'Extra Charge Amount Credited': 'Extra Charge Amount Credited',
'Failed to get access token': 'Failed to get access token',
'Add your parcel image.': 'Add your parcel image.',
'Please enter sender name': 'Please enter sender name',
'Please enter sender mobile': 'Please enter sender mobile',
'Please enter sender address': 'Please enter sender address',
'Please enter receiver name': 'Please enter receiver name',
'Please enter receiver mobile': 'Please enter receiver mobile',
'Please enter receiver address': 'Please enter receiver address',
'Please select scheduled date': 'Please select scheduled date',
'Please select scheduled time': 'Please select scheduled time',
'Please select parcel weight': 'Please select parcel weight',
'Please select both sender and receiver locations': 'Please select both sender and receiver locations',
"Sender's location to receiver's location should be more than 1 km.": "Sender's location to receiver's location should be more than 1 km.",
"Something went wrong while booking.": "Something went wrong while booking.",
"Cab Amount debited": "Cab Amount debited",
"Stop": "Stop",
'Departure': 'Departure',
'Destination': 'Destination',
'In Transit': 'In Transit',
'Order Accepted': 'Order Accepted',
'Driver Accepted': 'Driver Accepted',
'Driver Pending': 'Driver Pending',
'Order Shipped': 'Order Shipped',
'Order Completed': 'Order Completed',
'Order Rejected': 'Order Rejected',
'Order Cancelled': 'Order Cancelled',
'Driver Rejected': 'Driver Rejected',
'You can only cancel before pickup.': 'You can only cancel before pickup.',
'Refund for cancelled parcel order': 'Refund for cancelled parcel order',
'success': 'success',
'Order cancelled successfully': 'Order cancelled successfully',
'Failed to cancel order:': 'Failed to cancel order:',
'Parcel Amount debited': 'Parcel Amount debited',
'Order placed successfully': 'Order placed successfully',
'Initializing payment...': 'Initializing payment...',
'Payment Unsuccessful!!': 'Payment Unsuccessful!!',
'Rating saved successfully.': 'Rating saved successfully.',
'Please add rate for food item.': 'Please add rate for food item.',
'Placing booking...': 'Placing booking...',
'Unable to fetch current location': 'Unable to fetch current location',
'Failed to calculate total:': 'Failed to calculate total:',
'Rental Amount debited': 'Rental Amount debited',
'Refund for cancelled booking': 'Refund for cancelled booking',
'Success': 'Success',
'Booking cancelled successfully': 'Booking cancelled successfully',
'Failed to cancel booking:': 'Failed to cancel booking:',
'email': 'email',
'Restaurants': 'Restaurants',
'Amount Top-up successfully': 'Amount Top-up successfully',
'Something want wrong please contact administrator': 'Something want wrong please contact administrator',
'Payment': 'Payment',
'Cancel Payment': 'Cancel Payment',
'Cancel Payment?': 'Cancel Payment?',
'Orange Money Payment': 'Orange Money Payment',
'Are you sure you want to cancel this payment?': 'Are you sure you want to cancel this payment?',
'No': 'No',
'Yes': 'Yes',
'Continue Payment': 'Continue Payment',
'Exit': 'Exit',
'Your cart already contains items from another restaurant. Would you like to replace them with items from this restaurant instead?':
'Your cart already contains items from another restaurant. Would you like to replace them with items from this restaurant instead?',
'Google map is not installed': 'Google map is not installed',
'Google Go map is not installed': 'Google Go map is not installed',
'Waze is not installed': 'Waze is not installed',
'Mapswithme is not installed': 'Mapswithme is not installed',
'YandexNavi is not installed': 'YandexNavi is not installed',
'yandexMaps map is not installed': 'yandexMaps map is not installed',
'Image failed to load.': 'Image failed to load.',
'You denied location permission forever. Please allow location permission from your app settings and receive more accurate delivery.':
'You denied location permission forever. Please allow location permission from your app settings and receive more accurate delivery.',
'close': 'close',
'Settings': 'Settings',
'Move the map to select a location': 'Move the map to select a location',
'Search place...': 'Search place...',
'Confirm Location': 'Confirm Location',
'PickUp Location': 'PickUp Location',
'Search location...': 'Search location...',
'Picked Location:': 'Picked Location:',
'No Location Picked': 'No Location Picked',
'Email is Required': 'Email is Required',
'Invalid Email': 'Invalid Email',
};

87
lib/main.dart Normal file
View File

@@ -0,0 +1,87 @@
import 'package:customer/screen_ui/splash_screen/splash_screen.dart';
import 'package:customer/service/localization_service.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:customer/themes/easy_loading_config.dart';
import 'package:customer/utils/preferences.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'controllers/global_setting_controller.dart';
import 'controllers/theme_controller.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(name: 'default', options: DefaultFirebaseOptions.currentPlatform);
await Preferences.initPref();
Get.put(ThemeController());
await configEasyLoading();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final themeController = Get.find<ThemeController>();
@override
Widget build(BuildContext context) {
Get.put(ThemeController());
return Obx(
() => GetMaterialApp(
debugShowCheckedModeBanner: false,
builder: (context, child) {
return SafeArea(bottom: true, top: false, child: EasyLoading.init()(context, child));
},
translations: LocalizationService(),
locale: LocalizationService.locale,
fallbackLocale: LocalizationService.locale,
themeMode: themeController.themeMode,
theme: ThemeData(
scaffoldBackgroundColor: AppThemeData.surface,
textTheme: TextTheme(bodyLarge: TextStyle(color: AppThemeData.grey900)),
appBarTheme: AppBarTheme(
backgroundColor: AppThemeData.surface,
foregroundColor: AppThemeData.grey900,
iconTheme: IconThemeData(color: AppThemeData.grey900),
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: AppThemeData.surface,
selectedItemColor: AppThemeData.primary300,
unselectedItemColor: AppThemeData.grey600,
selectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
unselectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
type: BottomNavigationBarType.fixed,
),
),
darkTheme: ThemeData(
scaffoldBackgroundColor: AppThemeData.surfaceDark,
textTheme: TextTheme(bodyLarge: TextStyle(color: AppThemeData.greyDark900)),
appBarTheme: AppBarTheme(
backgroundColor: AppThemeData.surfaceDark,
foregroundColor: AppThemeData.greyDark900,
iconTheme: IconThemeData(color: AppThemeData.greyDark900),
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: AppThemeData.grey900,
selectedItemColor: AppThemeData.primary300,
unselectedItemColor: AppThemeData.grey300,
selectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
unselectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
type: BottomNavigationBarType.fixed,
),
),
home: GetBuilder<GlobalSettingController>(
init: GlobalSettingController(),
builder: (context) {
return const SplashScreen();
},
),
),
);
}
}

View File

@@ -0,0 +1,21 @@
class AdminCommission {
String? amount;
bool? isEnabled;
String? commissionType;
AdminCommission({this.amount, this.isEnabled, this.commissionType});
AdminCommission.fromJson(Map<String, dynamic> json) {
amount = json['commission'].toString();
isEnabled = json['enable'];
commissionType = json['type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['commission'] = amount;
data['enable'] = isEnabled;
data['type'] = commissionType;
return data;
}
}

View File

@@ -0,0 +1,97 @@
import 'package:cloud_firestore/cloud_firestore.dart';
class AdvertisementModel {
String? coverImage;
Timestamp? createdAt;
String? description;
Timestamp? endDate;
String? id;
bool? paymentStatus;
String? priority;
String? profileImage;
bool? showRating;
bool? showReview;
Timestamp? startDate;
String? status;
String? title;
String? type;
String? vendorId;
String? video;
bool? isPaused;
Timestamp? updatedAt;
String? canceledNote;
String? pauseNote;
AdvertisementModel({
this.coverImage,
this.createdAt,
this.description,
this.endDate,
this.id,
this.paymentStatus,
this.priority,
this.profileImage,
this.showRating,
this.showReview,
this.startDate,
this.status,
this.title,
this.type,
this.vendorId,
this.video,
this.isPaused,
this.updatedAt,
this.canceledNote,
this.pauseNote,
});
factory AdvertisementModel.fromJson(Map<String, dynamic> json) {
return AdvertisementModel(
coverImage: json['coverImage'],
createdAt: json['createdAt'],
description: json['description'],
endDate: json['endDate'],
id: json['id'],
paymentStatus: json['paymentStatus'],
priority: json['priority'],
profileImage: json['profileImage'],
showRating: json['showRating'],
showReview: json['showReview'],
startDate: json['startDate'],
status: json['status'],
title: json['title'],
type: json['type'],
vendorId: json['vendorId'],
video: json['video'],
isPaused: json['isPaused'],
updatedAt: json['updatedAt'],
canceledNote: json['canceledNote'],
pauseNote: json['pauseNote']);
}
Map<String, dynamic> toJson() {
return {
'coverImage': coverImage,
'createdAt': createdAt,
'description': description,
'endDate': endDate,
'id': id,
'paymentStatus': paymentStatus,
'priority': priority,
'profileImage': profileImage,
'showRating': showRating,
'showReview': showReview,
'startDate': startDate,
'status': status,
'title': title,
'type': type,
'vendorId': vendorId,
'video': video,
'isPaused': isPaused,
'updatedAt': updatedAt,
'canceledNote': canceledNote,
'pauseNote': pauseNote,
};
}
}

View File

@@ -0,0 +1,18 @@
class AttributesModel {
String? id;
String? title;
AttributesModel({this.id, this.title});
AttributesModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['title'] = title;
return data;
}
}

View File

@@ -0,0 +1,39 @@
class BannerModel {
String? id;
int? setOrder;
String? position;
String? sectionId;
String? photo;
String? title;
String? redirect_type;
String? redirect_id;
bool? isPublish;
BannerModel({this.id, this.setOrder, this.position, this.redirect_type, this.redirect_id, this.sectionId, this.photo, this.title, this.isPublish});
BannerModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
position = json['position'];
sectionId = json['sectionId'];
setOrder = json['set_order'];
photo = json['photo'];
title = json['title'];
isPublish = json['is_publish'];
redirect_type = json['redirect_type'];
redirect_id = json['redirect_id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['position'] = position;
data['sectionId'] = sectionId;
data['set_order'] = setOrder;
data['photo'] = photo;
data['title'] = title;
data['is_publish'] = isPublish;
data['redirect_type'] = redirect_type;
data['redirect_id'] = redirect_id;
return data;
}
}

View File

@@ -0,0 +1,27 @@
class BrandsModel {
String? photo;
String? sectionId;
String? id;
String? title;
bool? isPublish;
BrandsModel({this.photo, this.sectionId, this.id, this.title, this.isPublish});
BrandsModel.fromJson(Map<String, dynamic> json) {
photo = json['photo'];
sectionId = json['sectionId'];
id = json['id'];
title = json['title'];
isPublish = json['is_publish'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['photo'] = photo;
data['sectionId'] = sectionId;
data['id'] = id;
data['title'] = title;
data['is_publish'] = isPublish;
return data;
}
}

View File

@@ -0,0 +1,192 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/models/tax_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/vehicle_type.dart';
class CabOrderModel {
String? status;
List<dynamic>? rejectedByDrivers;
String? couponId;
Timestamp? scheduleDateTime;
String? duration;
bool? roundTrip;
bool? paymentStatus;
String? discount;
String? destinationLocationName;
String? authorID;
Timestamp? createdAt;
DestinationLocation? destinationLocation;
String? adminCommissionType;
String? sourceLocationName;
String? rideType;
List<TaxModel>? taxSetting;
Timestamp? triggerDelevery;
String? id;
String? adminCommission;
String? couponCode;
Timestamp? scheduleReturnDateTime;
String? sectionId;
String? tipAmount;
String? distance;
String? vehicleId;
String? paymentMethod;
VehicleType? vehicleType;
String? otpCode;
DestinationLocation? sourceLocation;
UserModel? author;
UserModel? driver;
String? driverId;
String? subTotal;
CabOrderModel({
this.status,
this.rejectedByDrivers,
this.scheduleDateTime,
this.duration,
this.roundTrip,
this.paymentStatus,
this.discount,
this.destinationLocationName,
this.authorID,
this.createdAt,
this.destinationLocation,
this.adminCommissionType,
this.sourceLocationName,
this.rideType,
this.taxSetting,
this.triggerDelevery,
this.id,
this.adminCommission,
this.couponCode,
this.couponId,
this.scheduleReturnDateTime,
this.sectionId,
this.tipAmount,
this.distance,
this.vehicleId,
this.paymentMethod,
this.vehicleType,
this.otpCode,
this.sourceLocation,
this.author,
this.subTotal,
this.driver,
this.driverId,
});
CabOrderModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
rejectedByDrivers = json['rejectedByDrivers'] ?? [];
couponId = json['couponId'];
scheduleDateTime = json['scheduleDateTime'];
duration = json['duration'];
roundTrip = json['roundTrip'];
paymentStatus = json['paymentStatus'];
discount = json['discount'] == null ?"0.0": json['discount'].toString();
destinationLocationName = json['destinationLocationName'];
authorID = json['authorID'];
createdAt = json['createdAt'];
destinationLocation = json['destinationLocation'] != null ? DestinationLocation.fromJson(json['destinationLocation']) : null;
adminCommissionType = json['adminCommissionType'];
sourceLocationName = json['sourceLocationName'];
rideType = json['rideType'];
if (json['taxSetting'] != null) {
taxSetting = <TaxModel>[];
json['taxSetting'].forEach((v) {
taxSetting!.add(TaxModel.fromJson(v));
});
}
triggerDelevery = json['trigger_delevery'];
id = json['id'];
adminCommission = json['adminCommission'];
couponCode = json['couponCode'];
scheduleReturnDateTime = json['scheduleReturnDateTime'];
sectionId = json['sectionId'];
tipAmount = json['tip_amount'];
distance = json['distance'];
vehicleId = json['vehicleId'];
paymentMethod = json['paymentMethod'];
vehicleType = json['vehicleType'] != null ? VehicleType.fromJson(json['vehicleType']) : null;
otpCode = json['otpCode'];
sourceLocation = json['sourceLocation'] != null ? DestinationLocation.fromJson(json['sourceLocation']) : null;
author = json['author'] != null ? UserModel.fromJson(json['author']) : null;
subTotal = json['subTotal'];
driver = json['driver'] != null ? UserModel.fromJson(json['driver']) : null;
driverId = json['driverId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['status'] = status;
// if (rejectedByDrivers != null) {
// data['rejectedByDrivers'] = rejectedByDrivers!.map((v) => v.toJson()).toList();
// }
if (rejectedByDrivers != null) {
data['rejectedByDrivers'] = rejectedByDrivers;
}
data['couponId'] = couponId;
data['scheduleDateTime'] = scheduleDateTime;
data['duration'] = duration;
data['roundTrip'] = roundTrip;
data['paymentStatus'] = paymentStatus;
data['discount'] = discount;
data['destinationLocationName'] = destinationLocationName;
data['authorID'] = authorID;
data['createdAt'] = createdAt;
if (destinationLocation != null) {
data['destinationLocation'] = destinationLocation!.toJson();
}
data['adminCommissionType'] = adminCommissionType;
data['sourceLocationName'] = sourceLocationName;
data['rideType'] = rideType;
if (taxSetting != null) {
data['taxSetting'] = taxSetting!.map((v) => v.toJson()).toList();
}
data['trigger_delevery'] = triggerDelevery!;
data['id'] = id;
data['adminCommission'] = adminCommission;
data['couponCode'] = couponCode;
data['scheduleReturnDateTime'] = scheduleReturnDateTime;
data['sectionId'] = sectionId;
data['tip_amount'] = tipAmount;
data['distance'] = distance;
data['vehicleId'] = vehicleId;
data['paymentMethod'] = paymentMethod;
data['driverId'] = driverId;
if (driver != null) {
data['driver'] = driver!.toJson();
}
if (vehicleType != null) {
data['vehicleType'] = vehicleType!.toJson();
}
data['otpCode'] = otpCode;
if (sourceLocation != null) {
data['sourceLocation'] = sourceLocation!.toJson();
}
if (author != null) {
data['author'] = author!.toJson();
}
data['subTotal'] = subTotal;
return data;
}
}
class DestinationLocation {
double? longitude;
double? latitude;
DestinationLocation({this.longitude, this.latitude});
DestinationLocation.fromJson(Map<String, dynamic> json) {
longitude = json['longitude'];
latitude = json['latitude'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['longitude'] = longitude;
data['latitude'] = latitude;
return data;
}
}

View File

@@ -0,0 +1,99 @@
import 'dart:convert';
class CartProductModel {
String? id;
String? categoryId;
String? name;
String? photo;
String? price;
String? discountPrice;
String? vendorID;
int? quantity;
String? extrasPrice;
List<dynamic>? extras;
VariantInfo? variantInfo;
CartProductModel({
this.id,
this.categoryId,
this.name,
this.photo,
this.price,
this.discountPrice,
this.vendorID,
this.quantity,
this.extrasPrice,
this.variantInfo,
this.extras,
});
CartProductModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
categoryId = json['category_id'];
name = json['name'];
photo = json['photo'];
price = json['price'] ?? "0.0";
discountPrice = json['discountPrice'] ?? "0.0";
vendorID = json['vendorID'];
quantity = json['quantity'];
extrasPrice = json['extras_price'];
extras = json['extras'] == "null" || json['extras'] == null
? null
: "String" == json['extras'].runtimeType.toString()
? List<dynamic>.from(jsonDecode(json['extras']))
: List<dynamic>.from(json['extras']);
variantInfo = json['variant_info'] == "null" || json['variant_info'] == null
? null
: "String" == json['variant_info'].runtimeType.toString()
? VariantInfo.fromJson(jsonDecode(json['variant_info']))
: VariantInfo.fromJson(json['variant_info']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['category_id'] = categoryId;
data['name'] = name;
data['photo'] = photo;
data['price'] = price;
data['discountPrice'] = discountPrice;
data['vendorID'] = vendorID;
data['quantity'] = quantity;
data['extras_price'] = extrasPrice;
data['extras'] = extras;
if (variantInfo != null) {
data['variant_info'] = variantInfo?.toJson(); // Handle null value
}
return data;
}
}
class VariantInfo {
String? variantId;
String? variantPrice;
String? variantSku;
String? variantImage;
Map<String, dynamic>? variantOptions;
VariantInfo({this.variantId, this.variantPrice, this.variantSku, this.variantImage, this.variantOptions});
VariantInfo.fromJson(Map<String, dynamic> json) {
variantId = json['variantId'] ?? '';
variantPrice = json['variantPrice'] ?? '';
variantSku = json['variantSku'] ?? '';
variantImage = json['variant_image'] ?? '';
variantOptions = json['variant_options'] ?? {};
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['variantId'] = variantId;
data['variantPrice'] = variantPrice;
data['variantSku'] = variantSku;
data['variant_image'] = variantImage;
data['variant_options'] = variantOptions;
return data;
}
}

Some files were not shown because too many files have changed in this diff Show More