Updated both apps' structure

master_new_changes
Faiz Hashmi 1 year ago
parent e2a5bbfb65
commit 424942bf58

@ -186,7 +186,7 @@
"updateBranch": "تحديث فرع",
"branches": "الفروع",
"requests": "الطلبات",
"noBranchFound" : "لم يتم العثور على فرع",
"noBranchFound": "لم يتم العثور على فرع",
"onlyProviderApp": "نأسف هذا التطبيق فقط لمقدمي الخدمات",
"pickAddress": "اختر العنوان",
"pickLocation": "اختر الموقع",
@ -202,19 +202,19 @@
"completeProfile2": "اكمل الملف الشخصي 2/3",
"completeProfile3": "اكمل الملف الشخصي 3/3",
"provider": "مزود",
"noRequeststoShow" : "لا توجد طلبات للعرض",
"noRequeststoShow": "لا توجد طلبات للعرض",
"myBranches": "فروعي",
"mergeAppointments" : "دمج المواعيد",
"addService" : "أضف الخدمة",
"selectServicestoAdd" : "حدد الخدمات التي تريد إضافتها",
"mergeAppointments": "دمج المواعيد",
"addService": "أضف الخدمة",
"selectServicestoAdd": "حدد الخدمات التي تريد إضافتها",
"noServiceFound": "لم يتم العثور على الخدمة",
"selectItems" : "اختيار العناصر",
"noItemSelectedYet" : "لم يتم تحديد أي عنصر بعد",
"totalAdditionalAmount" : "إجمالي المبلغ الإضافي",
"sar" : "ريال سعودي",
"cancel" : "يلغي",
"add" : "يضيف",
"itemsAddedSuccessfully" : "تمت إضافة العناصر بنجاح",
"selectItems": "اختيار العناصر",
"noItemSelectedYet": "لم يتم تحديد أي عنصر بعد",
"totalAdditionalAmount": "إجمالي المبلغ الإضافي",
"sar": "ريال سعودي",
"cancel": "يلغي",
"add": "يضيف",
"itemsAddedSuccessfully": "تمت إضافة العناصر بنجاح",
"pleaseSelectItems": "يرجى اختيار العناصر",
"totalAmount": "المبلغ الإجمالي",
"searchItems": "البحث عن العناصر",
@ -568,16 +568,17 @@
"customer": "العميل",
"amountVAR": "كمية",
"accept": "قبول",
"amountVAR": "كمية",
"nowVar": "الآن",
"whendoyouWanttoUpgrade": "متى تريد الترقية",
"yourSubscriptionUpgradeAffectingFrom": "سيتم ترقية اشتراكك الآن. ساري المفعول من",
"upgradeAfterCurrentExpiry": "الترقية بعد انتهاء الاشتراك الحالي",
"yourSubscriptionUpgradeCurrentSubscriptionAffectingFrom": "سيتم ترقية اشتراكك بعد انتهاء اشتراكك الحالي. ساري المفعول من",
"upgradeVar": "ترقية",
"whendoyouWanttoRenew" : "متى تريد التجديد",
"renewVar" : "تجديد",
"whendoyouWanttoRenew": "متى تريد التجديد",
"renewVar": "تجديد",
"requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.",
"acceptOfferConfirmation": "هل تريد قبول هذا العرض؟",
"acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض."
"acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض.",
"noUpcomingAppointments": "لا يوجد موعد قادم متاح",
"addNewAppointment": "إضافة موعد جديد"
}

@ -423,93 +423,93 @@
"reserveAd": "Reserve Ad",
"reservationAmount": "Reservation Amount",
"belowAmountPayLater": "Below Amount that you will pay later",
"carPrice":"Car Price",
"vatExcluded":"VAT Excluded",
"carInsuranceService":"Car insurance Service",
"toBeDecided":"To be Decided",
"registrationCarPlates":"Registration & Car Plates",
"homeDeliveryService":"Home Delivery Service",
"specialServicechargesInsuranceDeliveryLocation":"Special service charges will be added based on desired insurance and delivery Location",
"estimated":"Estimated",
"servicesReservingAd":"Some services are mandatory while reserving Ad",
"completeReservation":"Complete Reservation",
"contact":"Contact",
"setDateandTime":"Set Date and Time",
"selectOffice":"Select Office",
"availableSlots":"Available Slots",
"bookAndPay":"Book and Pay",
"reservationAmounts":"Reservation Amounts",
"tax":"Tax",
"carPrice": "Car Price",
"vatExcluded": "VAT Excluded",
"carInsuranceService": "Car insurance Service",
"toBeDecided": "To be Decided",
"registrationCarPlates": "Registration & Car Plates",
"homeDeliveryService": "Home Delivery Service",
"specialServicechargesInsuranceDeliveryLocation": "Special service charges will be added based on desired insurance and delivery Location",
"estimated": "Estimated",
"servicesReservingAd": "Some services are mandatory while reserving Ad",
"completeReservation": "Complete Reservation",
"contact": "Contact",
"setDateandTime": "Set Date and Time",
"selectOffice": "Select Office",
"availableSlots": "Available Slots",
"bookAndPay": "Book and Pay",
"reservationAmounts": "Reservation Amounts",
"tax": "Tax",
"adsFilter": "Ads Filter",
"searchByCity":"Search By City",
"selectCity":"Select City",
"searchByBrandName":"Search By Brand Name",
"selectVehicleBrand":"Select Vehicle Brand",
"searchByVehicleYear":"Search By Vehicle Year",
"selectYear":"Select Year",
"searchByAdOwner":"Search By Ad Owner",
"selectOwner":"Select Owner",
"search":"Search",
"clearFilters":"Clear Filters",
"book":"Book",
"markAsSold":"Mark As Sold",
"deactivateAd":"Deactivate Ad",
"doWantDeactivateAd":"Do you want to the Deactivate this Ad?",
"stoptheBuyers":"We will stop showing this ad to the buyers",
"cancelReservation":"Cancel Reservation",
"reasonForCancellation":"Reason for Cancellation",
"doWantCancelReservation":"Do you want to cancel the reservation",
"yourAdVisibletoBuy.":"Your ad reservation will be cancelled and this ad will be again visible to everyone to buy",
"completeDeal":"Complete Deal",
"uploadBankReceipt":"Upload Bank Receipt",
"notesForAdmin":"Notes For Admin",
"extendAd":"Extend Ad",
"updateAdDetails":"Do you want to update the Ad Details",
"durationExtendingAd":"You can change the ad duration and details before extending the ad",
"waitingAdminsResponse":"Waiting for Admins Response",
"cancelledByOwner":"Cancelled by Owner",
"cancelledByAdmin":"Cancelled by Admin",
"reservationTimeOver":"Reservation Time Over",
"paymentVerified":"Payment Verified",
"rejectedFormAdmin":"Rejected form Admin",
"waitingAdminPost":"Waiting for admin to post",
"waitingAdminsApproval":"Waiting for Admins Approval",
"sold":"Sold",
"noAdsShow":"No Ads to show",
"damagePartList":"Damage Part List",
"searchPart":"Search Part",
"addSpecialService":"Add Special Service",
"vehicleVar":"Vehicle",
"detailsVar":"Details",
"damageVar":"Damage",
"searchByCity": "Search By City",
"selectCity": "Select City",
"searchByBrandName": "Search By Brand Name",
"selectVehicleBrand": "Select Vehicle Brand",
"searchByVehicleYear": "Search By Vehicle Year",
"selectYear": "Select Year",
"searchByAdOwner": "Search By Ad Owner",
"selectOwner": "Select Owner",
"search": "Search",
"clearFilters": "Clear Filters",
"book": "Book",
"markAsSold": "Mark As Sold",
"deactivateAd": "Deactivate Ad",
"doWantDeactivateAd": "Do you want to the Deactivate this Ad?",
"stoptheBuyers": "We will stop showing this ad to the buyers",
"cancelReservation": "Cancel Reservation",
"reasonForCancellation": "Reason for Cancellation",
"doWantCancelReservation": "Do you want to cancel the reservation",
"yourAdVisibletoBuy.": "Your ad reservation will be cancelled and this ad will be again visible to everyone to buy",
"completeDeal": "Complete Deal",
"uploadBankReceipt": "Upload Bank Receipt",
"notesForAdmin": "Notes For Admin",
"extendAd": "Extend Ad",
"updateAdDetails": "Do you want to update the Ad Details",
"durationExtendingAd": "You can change the ad duration and details before extending the ad",
"waitingAdminsResponse": "Waiting for Admins Response",
"cancelledByOwner": "Cancelled by Owner",
"cancelledByAdmin": "Cancelled by Admin",
"reservationTimeOver": "Reservation Time Over",
"paymentVerified": "Payment Verified",
"rejectedFormAdmin": "Rejected form Admin",
"waitingAdminPost": "Waiting for admin to post",
"waitingAdminsApproval": "Waiting for Admins Approval",
"sold": "Sold",
"noAdsShow": "No Ads to show",
"damagePartList": "Damage Part List",
"searchPart": "Search Part",
"addSpecialService": "Add Special Service",
"vehicleVar": "Vehicle",
"detailsVar": "Details",
"damageVar": "Damage",
"partsVar": "Parts",
"additional":"Additional",
"review":"Review",
"additional": "Additional",
"review": "Review",
"adVar": "Ad",
"updateAd":"Update Ad",
"createAd":"Create Ad",
"next":"Next",
"submitAd":"Submit Ad",
"selectAdType":"Select Ad Type",
"validUntilSubscriptionExpiration":"Valid Until Subscription Expiration",
"adsRemainingVar ":"Ads Remaining",
"youLeftAdsGivenSubscription":"You have left with 05 out of 50 ads given in the subscription.",
"updateSubscription":"Update Subscription",
"workInProgress":"Work In Progress",
"visitCompleted":"Visit Completed",
"youWantCancelAppointment":"Do you want to cancel this appointment?",
"appointmentCancelledCannotUndoAction":"Your appointment will be cancelled and you cannot undo this action.",
"appointment":"Appointment",
"rescheduleAppointment":"Reschedule Appointment",
"payforAppointment":"Pay for Appointment",
"appointmentsFilter":"Appointments Filter",
"searchByProvider":"Search By Provider",
"selectProvider":"Select Provider",
"searchByBranch":"Search By Branch",
"searchByCategory":"Search By Category",
"selectCategory":"Select Category",
"searchByService":"Search By Service",
"selectServices":"Select Services",
"updateAd": "Update Ad",
"createAd": "Create Ad",
"next": "Next",
"submitAd": "Submit Ad",
"selectAdType": "Select Ad Type",
"validUntilSubscriptionExpiration": "Valid Until Subscription Expiration",
"adsRemainingVar ": "Ads Remaining",
"youLeftAdsGivenSubscription": "You have left with 05 out of 50 ads given in the subscription.",
"updateSubscription": "Update Subscription",
"workInProgress": "Work In Progress",
"visitCompleted": "Visit Completed",
"youWantCancelAppointment": "Do you want to cancel this appointment?",
"appointmentCancelledCannotUndoAction": "Your appointment will be cancelled and you cannot undo this action.",
"appointment": "Appointment",
"rescheduleAppointment": "Reschedule Appointment",
"payforAppointment": "Pay for Appointment",
"appointmentsFilter": "Appointments Filter",
"searchByProvider": "Search By Provider",
"selectProvider": "Select Provider",
"searchByBranch": "Search By Branch",
"searchByCategory": "Search By Category",
"selectCategory": "Select Category",
"searchByService": "Search By Service",
"selectServices": "Select Services",
"modifyPackage": "Modify Package",
"schedule": "Schedule",
"serviceLocation": "Service Location:",
@ -527,13 +527,13 @@
"dateAndTime": "Date and Time",
"timeLocation": "Time & Location",
"serviceCharges": "Service Charges",
"locationCharges" : "Location Charges",
"locationCharges": "Location Charges",
"payableNow": "Payable Now",
"remainingAmount": "Remaining Amount",
"branchesFilter": "Branches Filter",
"searchByDistance": "Search By Distance",
"searchByDistance": "Search By Distance",
"searchByMinimumRatings": "Search By Minimum Ratings",
"chat": "Chat",
"chat": "Chat",
"noRequestsShow": "No Requests to show.",
"typeMessageHere": "Type your message here..",
"reject": "Reject",
@ -561,7 +561,7 @@
"termPrivacy": "Term & Privacy",
"inviteFriends": "Invite Friends",
"more": "More",
"language" :"Language",
"language": "Language",
"mySubscriptions": "My Subscription",
"subscriptions": "Subscriptions",
"defineLicenses": "Define Licenses",
@ -571,14 +571,15 @@
"amountVAR": "Amount",
"requestAlreadyInProgress": "This request is already in progress.",
"acceptOfferConfirmation": "Do you want to accept this offer?",
"acceptOfferConfirmationMessage": "This offer will be accepted and you will pay the requested amount to the buyer in given time or else this offer will be cancelled."
"acceptOfferConfirmationMessage": "This offer will be accepted and you will pay the requested amount to the buyer in given time or else this offer will be cancelled.",
"nowVar": "Now",
"whendoyouWanttoUpgrade": "When do you want to upgrade",
"yourSubscriptionUpgradeAffectingFrom": "Your subscription will upgrade now. Affecting from",
"upgradeAfterCurrentExpiry": "Upgrade after current expiry",
"yourSubscriptionUpgradeCurrentSubscriptionAffectingFrom": "Your subscription will upgrade after you current subscription will end. Affecting from",
"upgradeVar": "Upgrade",
"whendoyouWanttoRenew" : "When do you want to renew",
"renewVar" : "Renew",
"whendoyouWanttoRenew": "When do you want to renew",
"renewVar": "Renew",
"noUpcomingAppointments": "No Upcoming Appointment Available.",
"addNewAppointment": "Add New Appointment"
}

@ -25,6 +25,14 @@ class AppState {
_deviceToken = value;
}
String? _deviceType;
String? get getDeviceType => _deviceType;
set setDeviceType(String value) {
_deviceType = value;
}
AppType currentAppType = AppType.provider;
UserType userType = UserType.customer;

@ -156,8 +156,11 @@ class ApiConsts {
//Chat
static String chatHubUrl = "$baseUrlServices/McHub";
static String messageIsReadUpdate = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update";
static String getChatMessages = "${baseUrlServices}api/RequestManagement/ReqOfferChat_Get";
static String messageIsReadUpdateForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update";
static String messageIsReadUpdateForAds = "${baseUrlServices}api/Advertisement/AdsChatIsRead_Update";
static String getChatMessagesForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChat_Get";
static String getChatMessagesForAds = "${baseUrlServices}api/Advertisement/AdsChat_Get";
static String getChatBuyersForAds = "${baseUrlServices}api/Advertisement/AdsChatBuyer_Get";
static List<String> closingUrls = ["PayFortResponse"];
}
@ -298,7 +301,6 @@ class MyFonts {
}
class SignalrConsts {
// Requests
static String receiveMessageRequestOffer = "ReceiveMessageRequestOffer";
static String sendMessageRequestOffer = "SendMessageRequestOffer";

@ -1,14 +1,24 @@
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/advertisement/ads_buyer_chats_list_view.dart';
import 'package:mc_common_app/views/advertisement/ads_detail_view.dart';
import 'package:mc_common_app/views/advertisement/ads_filter_view.dart';
import 'package:mc_common_app/views/advertisement/create_ad_view.dart';
import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart';
import 'package:mc_common_app/views/chat/chat_view.dart';
import 'package:mc_common_app/views/payments/payment_methods_view.dart';
import 'package:mc_common_app/views/profile/profile_view.dart';
import 'package:mc_common_app/views/requests/create_request_page.dart';
import 'package:mc_common_app/views/requests/offer_list_page.dart';
import 'package:mc_common_app/views/setting_options/provider_license_page.dart';
import 'package:mc_common_app/views/setting_options/setting_option_help.dart';
import 'package:mc_common_app/views/setting_options/setting_options_faqs.dart';
import 'package:mc_common_app/views/setting_options/setting_options_invite_friends.dart';
import 'package:mc_common_app/views/setting_options/setting_options_language.dart';
import 'package:mc_common_app/views/user/change_email_page.dart';
import 'package:mc_common_app/views/user/change_mobile_page.dart';
import 'package:mc_common_app/views/user/change_password_page.dart';
@ -67,6 +77,7 @@ class AppRoutes {
static const String adsDetailView = "/adsDetailView";
static const String createAdView = "/createAdView";
static const String adsFilterView = "/adsFilterView";
static const String adsBuyerChatsListView = "/adsBuyersChatListView";
// Payments
static const String paymentMethodsView = "/paymentMethodsView";
@ -116,28 +127,12 @@ class AppRoutes {
forgetPassword: (context) => const ForgetPasswordPage(),
loginVerification: (context) => const LoginVerificationPage(),
loginWithPassword: (context) => const LoginWithPassword(),
loginMethodSelection: (context) =>
LoginMethodSelectionPage(ModalRoute
.of(context)!
.settings
.arguments as String),
completeProfile: (context) =>
CompleteProfilePage(ModalRoute
.of(context)!
.settings
.arguments as RegisterUserRespModel),
loginMethodSelection: (context) => LoginMethodSelectionPage(ModalRoute.of(context)!.settings.arguments as String),
completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUserRespModel),
verifyPassword: (context) => VerifyPasswordPage(),
confirmNewPasswordPage: (context) =>
ConfirmNewPasswordPage(ModalRoute
.of(context)!
.settings
.arguments as String),
confirmNewPasswordPage: (context) => ConfirmNewPasswordPage(ModalRoute.of(context)!.settings.arguments as String),
changePassword: (context) => const ChangePasswordPage(),
forgetPasswordMethodPage: (context) =>
ForgetPasswordMethodPage(ModalRoute
.of(context)!
.settings
.arguments as String),
forgetPasswordMethodPage: (context) => ForgetPasswordMethodPage(ModalRoute.of(context)!.settings.arguments as String),
changeMobilePage: (context) => ChangeMobilePage(),
changeEmailPage: (context) => const ChangeEmailPage(),
editAccountPage: (context) => const EditAccountPage(),
@ -145,6 +140,19 @@ class AppRoutes {
settingOptionsLanguages: (context) => const SettingOptionsLanguage(),
settingOptionsHelp: (context) => const SettingOptionsHelp(),
providerLicensePage: (context) => ProviderLicensePage(),
// common pages
AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
AppRoutes.createAdView: (context) => const CreateAdView(),
AppRoutes.adsFilterView: (context) => const AdsFilterView(),
AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(isProvider: ModalRoute.of(context)!.settings.arguments as bool),
AppRoutes.chatView: (context) => ChatView(chatViewArguments: ModalRoute.of(context)!.settings.arguments as ChatViewArguments),
AppRoutes.offersListPage: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments),
AppRoutes.adsBuyerChatsListView: (context) => AdsBuyerChatsListView(buyersListViewArguments: ModalRoute.of(context)!.settings.arguments as List<BuyersChatForAdsModel>),
AppRoutes.createRequestPage: (context) => const CreateRequestPage(),
AppRoutes.settingOptionsFaqs: (context) => const SettingOptionsFAQs(),
AppRoutes.settingOptionsInviteFriends: (context) => const SettingOptionsInviteFriends(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes),
};
}
@ -169,9 +177,10 @@ class ChatViewArgumentsForRequest {
}
class ChatViewArgumentsForAd {
final AdDetailsModel? adDetailsModel;
final String? receiverUserID;
final int? adsID;
ChatViewArgumentsForAd({required this.adDetailsModel});
ChatViewArgumentsForAd({required this.receiverUserID, required this.adsID});
}
class ChatViewArguments {

@ -234,6 +234,9 @@ extension AppointmentStatusToInt on AppointmentStatusEnum {
case AppointmentStatusEnum.visitCompleted:
return 8;
case AppointmentStatusEnum.allAppointments:
return 0;
default:
return 0;
}

File diff suppressed because it is too large Load Diff

@ -558,5 +558,7 @@ abstract class LocaleKeys {
static const requestAlreadyInProgress = 'requestAlreadyInProgress';
static const acceptOfferConfirmation = 'acceptOfferConfirmation';
static const acceptOfferConfirmationMessage = 'acceptOfferConfirmationMessage';
static const noUpcomingAppointments = 'noUpcomingAppointments';
static const addNewAppointment = 'addNewAppointment';
}

@ -0,0 +1,21 @@
class BuyersChatForAdsModel {
int? id;
String? buyerUserID;
String? buyerName;
int? adsID;
int? unReadMessagesCount;
String? lastMessage;
String? lastMessageDateTime;
BuyersChatForAdsModel({this.id, this.buyerUserID, this.buyerName, this.adsID});
BuyersChatForAdsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
buyerUserID = json['buyerUserID'];
buyerName = json['buyerName'];
adsID = json['adsID'];
unReadMessagesCount = json['unReadCount'];
lastMessage = json['lastMessage'];
lastMessageDateTime = json['lastMessageDateTime'];
}
}

@ -1,19 +1,15 @@
import 'dart:convert';
import 'dart:developer';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart';
import 'package:mc_common_app/models/advertisment_models/pdf_receipt_model.dart';
import 'package:mc_common_app/models/advertisment_models/reserved_ads_models.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -26,6 +22,13 @@ abstract class AdsRepo {
Future<List<AdDetailsModel>> getAllAds({required bool isMyAds});
Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({
List<String>? cityIdsList,
List<String>? vehicleModelYearIdsList,
List<String>? vehicleBrandIdsList,
List<String>? createdByRolesIdsList,
});
Future<List<AdDetailsModel>> getMyReservedAds();
Future<List<AdDetailsModel>> getMyAds();
@ -43,6 +46,8 @@ abstract class AdsRepo {
Future<GenericRespModel> createReserveAd({required int adId});
Future<GenericRespModel> uploadBankReceiptsOnReserveDealDone({required int adId, required String detailNote, required List<PdfReceiptModel> pdfReceiptsList});
Future<List<BuyersChatForAdsModel>> getChatBuyersForAds({required int adsID});
}
class AdsRepoImp implements AdsRepo {
@ -152,7 +157,8 @@ class AdsRepoImp implements AdsRepo {
};
var allAdsParams = {
"AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
"IsPaid": "true", //only Active ADS
"isActive": "true", //only Active ADS
"isExplore": "true"
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
@ -165,6 +171,29 @@ class AdsRepoImp implements AdsRepo {
return vehicleAdsDetails;
}
@override
Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters(
{List<String>? cityIdsList, List<String>? vehicleModelYearIdsList, List<String>? vehicleBrandIdsList, List<String>? createdByRolesIdsList}) async {
var parameters = {
"CityIDs": cityIdsList ?? [],
"VehicleBrandIDs": vehicleBrandIdsList ?? [],
"VehicleModelYearIDs": vehicleModelYearIdsList ?? [],
"CreatedByRoles": createdByRolesIdsList ?? [],
"AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
"isActive": "true", //only Active ADS
"isExplore": "true"
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleAdsGet,
queryParameters: parameters,
);
List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], false));
return vehicleAdsDetails;
}
@override
Future<List<AdDetailsModel>> getMyReservedAds() async {
var params = {
@ -188,9 +217,7 @@ class AdsRepoImp implements AdsRepo {
}
Future<List<AdDetailsModel>> getAdsPerSpecificIds({required List<String> ids, required List<MyReservedAdsRespModel> reservedAds}) async {
var params = {
"AdsIDs": ids,
};
var params = {"AdsIDs": ids, "isActive": "true"};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
@ -381,4 +408,20 @@ class AdsRepoImp implements AdsRepo {
return Future.value(adsGenericModel);
}
@override
Future<List<BuyersChatForAdsModel>> getChatBuyersForAds({required int adsID}) async {
var queryParameters = {"AdsID": adsID.toString()};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getChatBuyersForAds,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
List<BuyersChatForAdsModel> buyersChatListForAds = [];
if (genericRespModel.data != null && genericRespModel.data.length > 0) {
buyersChatListForAds = List.generate(genericRespModel.data.length, (index) => BuyersChatForAdsModel.fromJson(genericRespModel.data[index]));
}
return buyersChatListForAds;
}
}

@ -15,10 +15,10 @@ abstract class AppointmentRepo {
Future<List<AppointmentListModel>> getMyAppointmentsForProvider(Map<String, dynamic> map);
Future<List<AppointmentListModel>> getMyAppointmentsForCustomersByFilters({
List<int>? providerIdsList,
List<int>? categoryIdsList,
List<int>? serviceIdsList,
List<int>? branchIdsList,
List<String>? providerIdsList,
List<String>? categoryIdsList,
List<String>? serviceIdsList,
List<String>? branchIdsList,
});
Future<MResponse> updateAppointmentStatus(Map<String, dynamic> map);
@ -191,48 +191,23 @@ class AppointmentRepoImp implements AppointmentRepo {
queryParameters: map,
ApiConsts.serviceProvidersAppointmentGet,
);
List<AppointmentListModel> appointmentList = await List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index]));
List<AppointmentListModel> appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index]));
return appointmentList;
}
@override
Future<List<AppointmentListModel>> getMyAppointmentsForCustomersByFilters({
List<int>? providerIdsList,
List<int>? categoryIdsList,
List<int>? serviceIdsList,
List<int>? branchIdsList,
List<String>? providerIdsList,
List<String>? categoryIdsList,
List<String>? serviceIdsList,
List<String>? branchIdsList,
}) async {
List<String> providerIds = [];
if (providerIdsList != null) {
for (var element in providerIdsList) {
providerIds.add(element.toString());
}
}
List<String> categoryIds = [];
if (categoryIdsList != null) {
for (var element in categoryIdsList) {
categoryIds.add(element.toString());
}
}
List<String> serviceIds = [];
if (serviceIdsList != null) {
for (var element in serviceIdsList) {
serviceIds.add(element.toString());
}
}
List<String> branchIds = [];
if (branchIdsList != null) {
for (var element in branchIdsList) {
branchIds.add(element.toString());
}
}
var params = {
"customerID": appState.getUser.data!.userInfo!.customerId.toString(),
"ServiceProviderIDs": providerIds,
"ProviderBranchIDs": categoryIds,
"ServiceIDs": serviceIds,
"CategoryIDs": categoryIds,
"ServiceProviderIDs": providerIdsList ?? [],
"ProviderBranchIDs": branchIdsList ?? [],
"ServiceIDs": serviceIdsList ?? [],
"CategoryIDs": categoryIdsList ?? [],
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,

@ -8,14 +8,31 @@ import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:signalr_core/signalr_core.dart';
abstract class ChatRepo {
Future<HubConnection> getHubConnection();
Future<void> markMessageAsRead({required int messageId});
Future<bool> markMessageAsRead({required List<int> messageIds, required ChatTypeEnum chatTypeEnum});
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int customerId, required int requestOfferId, required int requestId, int pageIndex = 0, int pageSize = 0});
Future<List<ChatMessageModel>> getUsersChatMessagesForRequests({
required int providerId,
required int customerId,
required int requestOfferId,
required int requestId,
int pageIndex = 0,
int pageSize = 0,
});
Future<List<ChatMessageModel>> getUsersChatMessagesForAds({
String? userID,
int? adID,
int? adsChatBuyerId,
required bool isForBuyer,
int pageIndex = 0,
int pageSize = 0,
});
}
class ChatRepoImp implements ChatRepo {
@ -41,21 +58,34 @@ class ChatRepoImp implements ChatRepo {
}
@override
Future<void> markMessageAsRead({required int messageId}) async {
var queryParameters = {
"id": messageId.toString(),
};
await apiClient.postJsonForObject(
Future<bool> markMessageAsRead({required List<int> messageIds, required ChatTypeEnum chatTypeEnum}) async {
String url = "";
if (chatTypeEnum == ChatTypeEnum.ads) {
url = ApiConsts.messageIsReadUpdateForAds;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
url = ApiConsts.messageIsReadUpdateForRequests;
}
var queryParameters = {"iDs": messageIds};
GenericRespModel genericRespModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.messageIsReadUpdate,
url,
queryParameters,
token: appState.getUser.data!.accessToken,
);
return genericRespModel.message == "";
}
@override
Future<List<ChatMessageModel>> getUsersChatMessages(
{required int providerId, required int customerId, required int requestOfferId, required int requestId, int pageIndex = 0, int pageSize = 0}) async {
Future<List<ChatMessageModel>> getUsersChatMessagesForRequests({
required int providerId,
required int customerId,
required int requestOfferId,
required int requestId,
int pageIndex = 0,
int pageSize = 0,
}) async {
var queryParameters = {
"ReqOfferID": requestOfferId.toString(),
"RequestID": requestId.toString(),
@ -66,7 +96,41 @@ class ChatRepoImp implements ChatRepo {
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getChatMessages,
ApiConsts.getChatMessagesForRequests,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
if (genericRespModel.messageStatus == 1 && genericRespModel.data != null) {
List<ChatMessageModel> chatMessages = List.generate(
genericRespModel.data.length,
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
);
return chatMessages;
}
return [];
}
@override
Future<List<ChatMessageModel>> getUsersChatMessagesForAds({String? userID, int? adID, int? adsChatBuyerId, required bool isForBuyer, int pageIndex = 0, int pageSize = 0}) async {
var parameterForBuyer = {
"UserID": userID.toString(),
"AdsID": adID.toString(),
"IsAdsBuyer": isForBuyer.toString(),
"PageSize": pageSize.toString(),
"PageIndex": pageIndex.toString(),
};
var parameterForSeller = {
"AdsChatBuyerID": adsChatBuyerId.toString(),
"IsAdsBuyer": isForBuyer.toString(),
"PageSize": pageSize.toString(),
"PageIndex": pageIndex.toString(),
};
var queryParameters = isForBuyer ? parameterForBuyer : parameterForSeller;
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getChatMessagesForAds,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);

@ -37,7 +37,7 @@ abstract class UserRepo {
Future<LoginPasswordRespModel> loginV2OTP(String userToken, String loginType);
Future<Response> loginV2OTPVerify(String userToken, String otp);
Future<Response> loginV2OTPVerify(String userToken, String otp, String deviceType, String deviceToken);
Future<RefreshToken> refreshTokenAPI(String token, String refreshToken);
@ -142,8 +142,13 @@ class UserRepoImp implements UserRepo {
}
@override
Future<Response> loginV2OTPVerify(String userToken, String otp) async {
var postParams = {"userToken": userToken, "userOTP": otp};
Future<Response> loginV2OTPVerify(
String userToken,
String otp,
String deviceType,
String deviceToken,
) async {
var postParams = {"userToken": userToken, "userOTP": otp, "deviceType": deviceType, "deviceToken": deviceToken};
return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.Login_V2_OTPVerify, postParams);
}

@ -41,6 +41,7 @@ class FirebaseMessagingServiceImp implements FirebaseMessagingService {
Future<void> initializeNotifications() async {
await requestPermissions();
AppState().setDeviceToken = await getFirebaseToken();
AppState().setDeviceType = Platform.isAndroid ? "1" : "2";
await Permission.notification.isDenied.then((bool value) {
if (value) {
Permission.notification.request();

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -16,6 +17,8 @@ import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_m
import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
@ -27,8 +30,10 @@ import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
class AdVM extends BaseVM {
final CommonRepo commonRepo;
@ -151,8 +156,8 @@ class AdVM extends BaseVM {
isExploreAdsTapped = value;
//To show the Active Ads
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.allAds);
applyFilterOnExploreAds(createdByRoleFilter: CreatedByRoleEnum.allAds);
// applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.allAds);
// applyFilterOnExploreAds(createdByRoleFilter: CreatedByRoleEnum.allAds);
// if (value) {
// await getExploreAds();
// }
@ -170,6 +175,8 @@ class AdVM extends BaseVM {
if (myAdsFilterOptions.isNotEmpty && exploreAdsFilterOptions.isNotEmpty) {
return;
}
log("myAdsEnums: ${myAdsEnums.length}");
log("exploreAdsEnums: ${exploreAdsEnums.length}");
if (myAdsEnums.isEmpty) {
myAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.myAdsFilterEnumId);
}
@ -1471,6 +1478,7 @@ class AdVM extends BaseVM {
// ************ ADS SEARCH VIEW ****************
Future<void> populateDataForAdFilter() async {
setState(ViewState.busy);
if (vehicleBrands.isEmpty) {
vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: -1);
}
@ -1478,6 +1486,7 @@ class AdVM extends BaseVM {
vehicleModelYears = await commonRepo.getVehicleModelYears(vehicleTypeId: -1);
}
vehicleCities = await commonRepo.getVehicleCities(countryId: -1); // fetch all the cities
setState(ViewState.idle);
}
ifAlreadyExist({required List<DropValue> list, required DropValue value}) {
@ -1546,8 +1555,8 @@ class AdVM extends BaseVM {
void updateSelectionVehicleAdOwnerId(SelectionModel id, {bool isForSearch = false}) {
if (isForSearch) {
EnumsModel owner = exploreAdsEnums.firstWhere((element) => element.id == id.selectedId);
DropValue ownerValue = DropValue(owner.id, "${owner.enumValueStr} Ads", "");
EnumsModel owner = exploreAdsEnums.firstWhere((element) => element.enumValue == id.selectedId);
DropValue ownerValue = DropValue(owner.enumValue, "${owner.enumValueStr} Ads", "");
if (!ifAlreadyExist(list: vehicleYearAdSearchHistory, value: ownerValue)) {
addToVehicleAdOwnerSearchHistory(value: ownerValue);
}
@ -1617,44 +1626,54 @@ class AdVM extends BaseVM {
vehicleAdOwnerSearchHistory.clear();
vehicleLocationAdSearchHistory.clear();
vehicleYearAdSearchHistory.clear();
adsFiltersCounter = 0;
getExploreAds();
notifyListeners();
}
void clearAdFilterSelections() {
vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleOwnerId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
}
Future<void> getAdsBasedOnFilters() async {
exploreAds.clear();
exploreAdsFilteredList.clear();
setState(ViewState.busy);
List<int> cityIdsList = [];
List<String> cityIdsList = [];
if (vehicleLocationAdSearchHistory.isNotEmpty) {
for (var element in vehicleLocationAdSearchHistory) {
cityIdsList.add(element.id);
cityIdsList.add(element.id.toString());
}
}
List<int> brandsIdsList = [];
List<String> brandsIdsList = [];
if (vehicleBrandsAdSearchHistory.isNotEmpty) {
for (var element in vehicleBrandsAdSearchHistory) {
brandsIdsList.add(element.id);
brandsIdsList.add(element.id.toString());
}
}
List<int> vehicleYearIdsList = [];
List<String> vehicleYearIdsList = [];
if (vehicleYearAdSearchHistory.isNotEmpty) {
for (var element in vehicleYearAdSearchHistory) {
vehicleYearIdsList.add(element.id);
vehicleYearIdsList.add(element.id.toString());
}
}
List<int> adOwnerIdsList = [];
List<String> adOwnerIdsList = [];
if (vehicleAdOwnerSearchHistory.isNotEmpty) {
for (var element in vehicleAdOwnerSearchHistory) {
adOwnerIdsList.add(element.id);
adOwnerIdsList.add(element.id.toString());
}
}
//
// myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(
// providerIdsList: providersIdsList.isNotEmpty ? providersIdsList : null,
// categoryIdsList: categoryIdsList.isNotEmpty ? categoryIdsList : null,
// serviceIdsList: servicesIdsList.isNotEmpty ? servicesIdsList : null,
// branchIdsList: branchesIdsList.isNotEmpty ? branchesIdsList : null,
// );
applyFilterOnExploreAds(createdByRoleFilter: CreatedByRoleEnum.allAds);
exploreAdsFilteredList = await adsRepo.getExploreAdsBasedOnFilters(
cityIdsList: cityIdsList,
createdByRolesIdsList: adOwnerIdsList,
vehicleBrandIdsList: brandsIdsList,
vehicleModelYearIdsList: vehicleYearIdsList,
);
setState(ViewState.idle);
}
@ -1809,15 +1828,46 @@ class AdVM extends BaseVM {
return specialServiceCards.indexWhere((element) => element.serviceSelectedId!.selectedId == id);
}
void onMessagesButtonPressed({required BuildContext context, required AdDetailsModel adDetailsModel}) {
ChatViewArgumentsForAd chatViewArgumentsForAd = ChatViewArgumentsForAd(adDetailsModel: adDetailsModel);
List<BuyersChatForAdsModel> buyersChatListForAds = [];
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.ads, chatViewArgumentsForAd: chatViewArgumentsForAd);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
void onMessagesButtonPressed({required BuildContext context, required AdDetailsModel adDetailsModel}) async {
final myUserID = AppState().getUser.data!.userInfo!.userId;
if (adDetailsModel.isMyAd != null && adDetailsModel.isMyAd!) {
await getBuyerChatsByAds(adsID: adDetailsModel.id!, context: context);
navigateWithName(context, AppRoutes.adsBuyerChatsListView, arguments: buyersChatListForAds);
} else {
ChatViewArgumentsForAd chatViewArgumentsForAd = ChatViewArgumentsForAd(receiverUserID: adDetailsModel.userID, adsID: adDetailsModel.id);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.ads, chatViewArgumentsForAd: chatViewArgumentsForAd);
final chatVM = context.read<ChatVM>();
await chatVM
.getUsersChatMessagesForAd(
context: context,
isForBuyer: true,
adsChatBuyerId: 1,
adID: adDetailsModel.id,
userID: myUserID,
)
.whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}
}
}
// Edit Work End Amir
Future<void> getBuyerChatsByAds({required int adsID, required BuildContext context}) async {
try {
Utils.showLoading(context);
List<BuyersChatForAdsModel> buyersChatList = await adsRepo.getChatBuyersForAds(adsID: adsID);
Utils.hideLoading(context);
buyersChatListForAds.clear();
buyersChatListForAds = buyersChatList;
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
}
}
class VehicleDamageCard {
List<ImageModel>? partImages;

@ -238,9 +238,7 @@ class AppointmentsVM extends BaseVM {
}
void removeServiceInCurrentAppointment(int index) {
int serviceId = servicesInCurrentAppointment
.elementAt(index)
.serviceProviderServiceId ?? -1;
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
servicesInCurrentAppointment.removeAt(index);
notifyListeners();
@ -275,8 +273,6 @@ class AppointmentsVM extends BaseVM {
// TODO: THIS SHOULD REMOVED AND ADDED IN THE ENUMS API
appointmentsFilterOptions.add(FilterListModel(title: "Work In Progress", isSelected: false, id: 7));
appointmentsFilterOptions.add(FilterListModel(title: "Visit Completed", isSelected: false, id: 8));
logger.i("appointmentsFilterOptions: ${appointmentsFilterOptions.length}");
notifyListeners();
}
@ -363,7 +359,8 @@ class AppointmentsVM extends BaseVM {
myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters();
// myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed ).toList();
myUpComingAppointments =
myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
setState(ViewState.idle);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
notifyListeners();
@ -391,7 +388,7 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.busy);
myAppointments = await appointmentRepo.getMyAppointmentsForProvider(map);
myFilteredAppointments = myAppointments;
myUpComingAppointments = await myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
setState(ViewState.idle);
}
@ -594,7 +591,7 @@ class AppointmentsVM extends BaseVM {
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return AppointmentServicePickBottomSheet();
return const AppointmentServicePickBottomSheet();
},
);
}
@ -657,8 +654,8 @@ class AppointmentsVM extends BaseVM {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(selectedService.isHomeSelected
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
@ -808,6 +805,7 @@ class AppointmentsVM extends BaseVM {
// BRANCHES RELATED
List<BranchDetailModel> nearbyBranches = [];
List<BranchDetailModel> myRecentBranches = [];
BranchDetailModel? selectedBranchModel;
List<ServiceModel> branchServices = [];
@ -852,6 +850,13 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.idle);
}
Future<void> getMyRecentBranches({bool isNeedToRebuild = false}) async {
myRecentBranches.clear();
if (isNeedToRebuild) setState(ViewState.busy);
myRecentBranches = await branchRepo.getAllNearBranchAndServices();
setState(ViewState.idle);
}
void getBranchCategories() async {
for (var value in selectedBranchModel!.branchServices!) {
if (!isCategoryAlreadyPresent(value.categoryId!)) {
@ -1081,10 +1086,10 @@ class AppointmentsVM extends BaseVM {
DropValue(
element.id ?? 0,
((element.categoryName!.isEmpty
? "N/A"
: countryCode == "SA"
? element.categoryNameN
: element.categoryName) ??
? "N/A"
: countryCode == "SA"
? element.categoryNameN
: element.categoryName) ??
"N/A"),
""),
);
@ -1388,42 +1393,42 @@ class AppointmentsVM extends BaseVM {
appointmentFilterBranchSearchHistory.clear();
appointmentFiltersCounter = 0;
clearAppointmentFilterSelections();
getMyAppointments();
notifyListeners();
}
Future<void> getAppointmentsBasedOnFilters() async {
nearbyBranches.clear();
setState(ViewState.busy);
List<int> providersIdsList = [];
List<String> providersIdsList = [];
if (appointmentFilterProviderSearchHistory.isNotEmpty) {
for (var element in appointmentFilterProviderSearchHistory) {
providersIdsList.add(element.id);
providersIdsList.add(element.id.toString());
}
}
List<int> categoryIdsList = [];
List<String> categoryIdsList = [];
if (appointmentFilterCategorySearchHistory.isNotEmpty) {
for (var element in appointmentFilterCategorySearchHistory) {
categoryIdsList.add(element.id);
categoryIdsList.add(element.id.toString());
}
}
List<int> servicesIdsList = [];
List<String> servicesIdsList = [];
if (appointmentFilterServicesSearchHistory.isNotEmpty) {
for (var element in appointmentFilterServicesSearchHistory) {
servicesIdsList.add(element.id);
servicesIdsList.add(element.id.toString());
}
}
List<int> branchesIdsList = [];
List<String> branchesIdsList = [];
if (appointmentFilterBranchSearchHistory.isNotEmpty) {
for (var element in appointmentFilterBranchSearchHistory) {
branchesIdsList.add(element.id);
branchesIdsList.add(element.id.toString());
}
}
myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(
providerIdsList: providersIdsList.isNotEmpty ? providersIdsList : null,
categoryIdsList: categoryIdsList.isNotEmpty ? categoryIdsList : null,
serviceIdsList: servicesIdsList.isNotEmpty ? servicesIdsList : null,
branchIdsList: branchesIdsList.isNotEmpty ? branchesIdsList : null,
providerIdsList: providersIdsList,
categoryIdsList: categoryIdsList,
serviceIdsList: servicesIdsList,
branchIdsList: branchesIdsList,
);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
setState(ViewState.idle);

@ -8,7 +8,6 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
@ -56,7 +55,6 @@ class ChatVM extends ChangeNotifier {
return;
}
logger.i(scrollController.position.maxScrollExtent);
scrollController.animateTo(
scrollController.position.maxScrollExtent + 200, // for the text field
duration: const Duration(seconds: 1),
@ -130,7 +128,7 @@ class ChatVM extends ChangeNotifier {
return isValidated;
}
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async {
Future<void> onNewMessageReceivedForRequestOffer({required List<ChatMessageModel> messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async {
if (AppState().currentAppType == AppType.customer) {
for (var msg in messages) {
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID);
@ -159,33 +157,55 @@ class ChatVM extends ChangeNotifier {
notifyListeners();
}
Future<void> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async {
for (var msg in messages) {
currentMessagesForAds.add(msg);
}
scrollChatDown();
notifyListeners();
}
void subscribeToReceiveRequestOfferMessages(BuildContext context) {
hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return;
List<ChatMessageModel> chat = [];
for (var message in arguments) {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceivedForRequestOffer(messages: chat, requestsVM: context.read<RequestsVM>());
logger.i(arguments);
// Utils.showToast(arguments.toString());
});
}
void subscribeToReceiveAdMessages(BuildContext context) {
hubConnection!.on(SignalrConsts.receiveMessageAds, (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return;
List<ChatMessageModel> chat = [];
for (var message in arguments) {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceivedForAds(messages: chat);
logger.i(arguments);
// Utils.showToast(arguments.toString());
});
}
Future<void> buildHubConnection(BuildContext context) async {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
try {
hubConnection = await chatRepo.getHubConnection();
await hubConnection!.start();
hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return;
List<ChatMessageModel> chat = [];
for (var message in arguments) {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceived(messages: chat, requestsVM: context.read<RequestsVM>());
logger.i(arguments);
Utils.showToast(arguments.toString());
});
subscribeToReceiveRequestOfferMessages(context);
subscribeToReceiveAdMessages(context);
hubConnection!.onclose((exception) {
logger.i("onClose: ${exception.toString()}");
buildHubConnection(context);
});
hubConnection!.onreconnecting((exception) => () {
logger.i("onReconnecting: ${exception.toString()}");
});
hubConnection!.onreconnected((connectionId) => () {
logger.i("onReconnected: ${connectionId.toString()}");
});
hubConnection!.onreconnecting((exception) => () => logger.i("onReconnecting: ${exception.toString()}"));
hubConnection!.onreconnected((connectionId) => () => logger.i("onReconnected: ${connectionId.toString()}"));
} catch (e) {
logger.i("Error: ${e.toString()}");
}
@ -208,24 +228,25 @@ class ChatVM extends ChangeNotifier {
}
if (hubConnection!.state == HubConnectionState.connected) {
final providerId = AppState().getUser.data!.userInfo!.providerId;
final obj = <String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": providerId,
"OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
"Comment": message,
},
};
logger.i(obj);
hubConnection!.invoke(
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": providerId,
"OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
"Comment": message,
},
}
],
args: <Object>[obj],
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
Utils.showToast(e.toString());
@ -233,22 +254,6 @@ class ChatVM extends ChangeNotifier {
});
}
logger.i(<String, dynamic>{
"ID": "", //here should be req offer ID
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"ID": "",
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": AppState().getUser.data!.userInfo!.providerId,
"OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
"Comment": message,
},
});
return true;
}
@ -271,7 +276,7 @@ class ChatVM extends ChangeNotifier {
final userId = AppState().getUser.data!.userInfo!.userId.toString();
final name = AppState().getUser.data!.userInfo!.firstName.toString();
logger.i((<String, dynamic>{
final obj = <String, dynamic>{
"ReceiverUserID": receiverId,
"SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
@ -279,21 +284,12 @@ class ChatVM extends ChangeNotifier {
"RequestID": requestId,
"ReqOfferID": latestOfferId,
// "ReqOffer": {}
}));
};
logger.i(obj);
hubConnection!.invoke(
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": latestOfferId,
// "ReqOffer": {}
}
],
args: <Object>[obj],
).catchError((e) {
logger.i("error in invoking SendMessage: ${e.toString()}");
Utils.showToast(e.toString());
@ -355,7 +351,7 @@ class ChatVM extends ChangeNotifier {
try {
int customerId = AppState().getUser.data!.userInfo!.customerId!;
Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessagesForRequests(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
serviceProviderOffersList[providerOfferIndex].chatMessages = chatMessages;
if (serviceProviderOffersList[providerOfferIndex].chatMessages != null) {
for (var message in serviceProviderOffersList[providerOfferIndex].chatMessages!) {
@ -384,7 +380,7 @@ class ChatVM extends ChangeNotifier {
try {
int providerId = AppState().getUser.data!.userInfo!.providerId!;
Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessagesForRequests(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context);
Utils.hideLoading(context);
} catch (e) {
@ -424,25 +420,26 @@ class ChatVM extends ChangeNotifier {
await buildHubConnection(context);
}
if (hubConnection!.state == HubConnectionState.connected) {
var obj = <String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": comments,
"RequestID": requestId,
"ReqOfferID": requestOfferID,
"ReqOffer": <String, dynamic>{
"ID": requestOfferID,
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": serviceProviderID,
"OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
"Comment": comments,
},
};
logger.i(obj);
hubConnection!.invoke(
SignalrConsts.sendMessageRequestOffer,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": comments,
"RequestID": requestId,
"ReqOfferID": requestOfferID,
"ReqOffer": <String, dynamic>{
"ID": requestOfferID,
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": serviceProviderID,
"OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
"Comment": comments,
},
}
],
args: <Object>[obj],
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
Utils.showToast(e.toString());
@ -450,31 +447,59 @@ class ChatVM extends ChangeNotifier {
});
}
logger.i(<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": comments,
"RequestID": requestId,
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"ID": requestOfferID,
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": serviceProviderID,
"OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(),
"Comment": comments,
},
});
return true;
}
// =================== Ads ======================
List<ChatMessageModel> currentMessagesForAds = [];
Future<void> getUsersChatMessagesForAd({required BuildContext context, int? adID, int? adsChatBuyerId, String? userID, required bool isForBuyer}) async {
try {
Utils.showLoading(context);
currentMessagesForAds = await chatRepo.getUsersChatMessagesForAds(userID: userID, adID: adID, isForBuyer: isForBuyer, adsChatBuyerId: adsChatBuyerId);
Utils.hideLoading(context);
List<int> unreadMessageIds = [];
for (var msg in currentMessagesForAds) {
if (!msg.isRead!) {
unreadMessageIds.add(msg.id!);
}
}
if (unreadMessageIds.isNotEmpty) {
await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.ads);
}
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
}
Future<bool> markMessagesAsRead(BuildContext context, List<int> messageIds, ChatTypeEnum chatTypeEnum) async {
bool status = false;
try {
Utils.showLoading(context);
status = await chatRepo.markMessageAsRead(messageIds: messageIds, chatTypeEnum: chatTypeEnum);
Utils.hideLoading(context);
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
status = false;
}
return status;
}
Future<bool> onTextMessageSendForAds({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
required AdDetailsModel adDetailsModel,
required int adId,
required BuildContext context,
}) async {
if (message.isEmpty) return false;
@ -487,18 +512,18 @@ class ChatVM extends ChangeNotifier {
if (hubConnection!.state == HubConnectionState.connected) {
final userId = AppState().getUser.data!.userInfo!.userId.toString();
final name = AppState().getUser.data!.userInfo!.firstName.toString();
final obj = <String, dynamic>{
"ReceiverUserID": receiverId,
// "SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"AdsID": adId,
};
logger.i("$obj");
hubConnection!.invoke(
SignalrConsts.sendMessageAds,
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"AdsID": adDetailsModel.id,
}
],
args: <Object>[obj],
).catchError((e) {
logger.i("error in invoking SendMessage: ${e.toString()}");
Utils.showToast(e.toString());
@ -509,26 +534,18 @@ class ChatVM extends ChangeNotifier {
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
chatText: message,
isMyMessage: true,
requestID: 0,
senderName: name,
senderUserID: userId,
chatMessageTypeEnum: ChatMessageTypeEnum.freeText,
receiverUserID: receiverId,
);
if (AppState().currentAppType == AppType.customer) {
} else {
currentMessagesForAds.add(chatMessageModel);
notifyListeners();
}
if (AppState().currentAppType == AppType.customer) {
} else {}
return true;
}
return false;

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
@ -30,7 +31,7 @@ class DashboardVmCustomer extends BaseVM {
int selectedNavbarBarIndex = 2;
void onNavbarTapped(int index) async {
print(AppState().getDeviceToken);
logger.i(AppState().getDeviceToken);
selectedNavbarBarIndex = index;
notifyListeners();
}
@ -60,54 +61,62 @@ class DashboardVmCustomer extends BaseVM {
}
}
onInitState(BuildContext context) async {
Future.wait<dynamic>([
context.read<RequestsVM>().populateRequestsFilterList(),
context.read<AppointmentsVM>().populateAppointmentsFilterList(),
context.read<AppointmentsVM>().populateBranchesFilterList(),
context.read<AdVM>().populateAdsFilterList(),
]);
}
Future<void> onRefresh(BuildContext context) async {
AdVM adVM = Provider.of<AdVM>(context, listen: false);
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
RequestsVM requestsVM = Provider.of<RequestsVM>(context, listen: false);
ChatVM chatVM = Provider.of<ChatVM>(context, listen: false);
if (appointmentsVM.myAppointments.isEmpty) {
await appointmentsVM.getMyAppointments();
}
appointmentsVM.populateBranchesFilterList();
appointmentsVM.populateAppointmentsFilterList();
adVM.populateAdsFilterList();
requestsVM.populateRequestsFilterList();
if (appointmentsVM.nearbyBranches.isEmpty) {
await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
}
if (adVM.myAds.isEmpty) {
await adVM.getMyAds();
}
if (adVM.exploreAds.isEmpty) {
await adVM.getExploreAds();
}
if (requestsVM.myRequests.isEmpty) {
await requestsVM.getRequests(appType: AppType.customer);
}
if (adVM.vehicleTypes.isEmpty) {
await adVM.getVehicleTypes();
}
await appointmentsVM.getMyAppointments();
await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
await appointmentsVM.getMyRecentBranches(); // to get my recent branches!
await adVM.getMyAds();
await adVM.getExploreAds();
await requestsVM.getRequests(appType: AppType.customer);
await adVM.getVehicleTypes();
await adVM.getVehicleAdsDuration();
await chatVM.buildHubConnection(context);
if (adVM.vehicleAdsDurations.isEmpty) {
await adVM.getVehicleAdsDuration();
}
// if (appointmentsVM.myAppointments.isEmpty) {
// await appointmentsVM.getMyAppointments();
// }
//
// if (appointmentsVM.nearbyBranches.isEmpty) {
// await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
// }
// if (appointmentsVM.myRecentBranches.isEmpty) {
// await appointmentsVM.getMyRecentBranches(); // to get my recent branches!
// }
//
// if (adVM.myAds.isEmpty) {
// await adVM.getMyAds();
// }
// if (adVM.exploreAds.isEmpty) {
// await adVM.getExploreAds();
// }
// if (requestsVM.myRequests.isEmpty) {
// await requestsVM.getRequests(appType: AppType.customer);
// }
//
// if (adVM.vehicleTypes.isEmpty) {
// await adVM.getVehicleTypes();
// }
//
// if (adVM.vehicleAdsDurations.isEmpty) {
// await adVM.getVehicleAdsDuration();
// }
await chatVM.buildHubConnection(context);
adVM.updateVehicleAdDurationId(
SelectionModel(
selectedId: adVM.vehicleAdsDurations.first.id ?? 0,
selectedOption: "${adVM.vehicleAdsDurations.first.days} Days",
itemPrice: adVM.vehicleAdsDurations.first.price!.toInt().toString(),
),
);
// adVM.updateVehicleAdDurationId(
// SelectionModel(
// selectedId: adVM.vehicleAdsDurations.first.id ?? 0,
// selectedOption: "${adVM.vehicleAdsDurations.first.days} Days",
// itemPrice: adVM.vehicleAdsDurations.first.price!.toInt().toString(),
// ),
// );
}
Future<ImageResponse> updateUserImage(String image) async {

@ -69,7 +69,7 @@ class RequestsVM extends BaseVM {
paramsForGetRequests = {
"pageSize": 100,
"pageIndex": 0,
"requestType": 0,
// "requestType": 0,
};
if (appType == AppType.provider) {
paramsForGetRequests.addEntries([MapEntry("providerID", AppState().getUser.data!.userInfo!.providerId)]);
@ -460,7 +460,7 @@ class RequestsVM extends BaseVM {
comment: message,
offerStatusText: "",
));
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);
context.read<ChatVM>().onNewMessageReceivedForRequestOffer(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);
if (!isFromChatScreen) {
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(

@ -347,7 +347,12 @@ class UserVM extends BaseVM {
//Utils.showLoading(context);
LoginPasswordRespModel user = await userRepo.loginV2OTP(userToken, loginType!);
if (user.messageStatus == 1) {
Response response2 = await userRepo.loginV2OTPVerify(user.data!.userToken ?? "", "9999");
Response response2 = await userRepo.loginV2OTPVerify(
user.data!.userToken ?? "",
"9999",
AppState().getDeviceType ?? "1",
AppState().getDeviceToken ?? "",
);
RegisterUserRespModel verifiedUser = RegisterUserRespModel.fromJson(jsonDecode(response2.body));
if (verifiedUser.messageStatus == 1) {
User user = User.fromJson(jsonDecode(response2.body));
@ -387,13 +392,18 @@ class UserVM extends BaseVM {
onClick: (String code) async {
pop(context);
Utils.showLoading(context);
Response response2 = await userRepo.loginV2OTPVerify(user.data!.userToken ?? "", code);
Response response2 = await userRepo.loginV2OTPVerify(
user.data!.userToken ?? "",
code,
AppState().getDeviceType ?? "1",
AppState().getDeviceToken ?? "",
);
Utils.hideLoading(context);
RegisterUserRespModel verifiedUser = RegisterUserRespModel.fromJson(jsonDecode(response2.body));
if (verifiedUser.messageStatus == 1) {
User user = User.fromJson(jsonDecode(response2.body));
if (appType == AppType.provider) {
if (user.data!.userInfo!.roleId == 5 || user.data!.userInfo!.roleId == 6 || user.data!.userInfo!.roleId == 7 ) {
if (user.data!.userInfo!.roleId == 5 || user.data!.userInfo!.roleId == 6 || user.data!.userInfo!.roleId == 7) {
AppState().setUser = user;
SharedPrefManager.setUserToken(user.data!.accessToken ?? "");
SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? "");
@ -455,7 +465,12 @@ class UserVM extends BaseVM {
onClick: (String code) async {
pop(context);
Utils.showLoading(context);
Response response2 = await userRepo.loginV2OTPVerify(user.data!.userToken ?? "", code);
Response response2 = await userRepo.loginV2OTPVerify(
user.data!.userToken ?? "",
code,
AppState().getDeviceType ?? "1",
AppState().getDeviceToken ?? "",
);
Utils.hideLoading(context);
RegisterUserRespModel verifiedUser = RegisterUserRespModel.fromJson(jsonDecode(response2.body));
if (verifiedUser.messageStatus == 1) {

@ -56,7 +56,7 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
("${adDuration.days}" + LocaleKeys.daysVar.tr())
("${adDuration.days}${LocaleKeys.daysVar.tr()}")
.toString()
.toText(fontSize: 16, isBold: true),
4.height,
@ -101,7 +101,7 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
SelectionModel(
selectedId: adDuration.id ?? 0,
selectedOption:
("${adDuration.days} " + LocaleKeys.daysVar.tr()),
("${adDuration.days} ${LocaleKeys.daysVar.tr()}"),
itemPrice: adDuration.price!.toInt().toString(),
),
);
@ -111,7 +111,7 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
SelectionModel(
selectedId: adDuration.id ?? 0,
selectedOption:
("${adDuration.days} " + LocaleKeys.daysVar.tr()),
("${adDuration.days} ${LocaleKeys.daysVar.tr()}"),
itemPrice: adDuration.price!.toInt().toString(),
),
);

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
class AdsBuyerChatsListView extends StatelessWidget {
final List<BuyersChatForAdsModel> buyersListViewArguments;
const AdsBuyerChatsListView({super.key, required this.buyersListViewArguments});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.chat.tr()),
body: buyersListViewArguments.isEmpty
? Center(child: LocaleKeys.noOffersShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: buyersListViewArguments.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
BuyersChatForAdsModel chatForAdsModel = buyersListViewArguments[index];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(chatForAdsModel.buyerName ?? "").toText(fontSize: 16, isBold: true),
if (chatForAdsModel.unReadMessagesCount != null && chatForAdsModel.unReadMessagesCount! > 0) ...[
Center(
child: "${chatForAdsModel.unReadMessagesCount ?? "1"}".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 22,
height: 22,
),
]
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
(chatForAdsModel.lastMessage ?? "").toText(color: MyColors.lightTextColor, fontSize: 12),
],
),
if (chatForAdsModel.lastMessageDateTime != null) ...[
DateTime.parse(chatForAdsModel.lastMessageDateTime!).getTimeAgo().toText(color: MyColors.lightTextColor),
],
// const Icon(
// Icons.arrow_forward,
// color: MyColors.darkIconColor,
// size: 18,
// ),
],
),
],
).onPress(() async {
ChatViewArgumentsForAd chatViewArgumentsForAd = ChatViewArgumentsForAd(receiverUserID: chatForAdsModel.buyerUserID, adsID: chatForAdsModel.adsID);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.ads, chatViewArgumentsForAd: chatViewArgumentsForAd);
final chatVM = context.read<ChatVM>();
await chatVM.getUsersChatMessagesForAd(context: context, isForBuyer: false, adsChatBuyerId: chatForAdsModel.id).whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
);
}
}

@ -5,9 +5,7 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';

@ -1,3 +1,6 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
@ -5,6 +8,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
@ -14,9 +18,31 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class AdsFilterView extends StatelessWidget {
class AdsFilterView extends StatefulWidget {
const AdsFilterView({super.key});
@override
State<AdsFilterView> createState() => _AdsFilterViewState();
}
class _AdsFilterViewState extends State<AdsFilterView> {
late AdVM adVM;
@override
void initState() {
adVM = context.read<AdVM>();
scheduleMicrotask(() async {
await adVM.populateDataForAdFilter();
});
super.initState();
}
@override
void dispose() {
adVM.clearAdFilterSelections();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -32,9 +58,14 @@ class AdsFilterView extends StatelessWidget {
),
body: Consumer<AdVM>(
builder: (BuildContext context, AdVM adVM, Widget? child) {
if (adVM.state == ViewState.busy) {
return const Center(
child: CircularProgressIndicator(),
);
}
return WillPopScope(
onWillPop: () async {
context.read<AdVM>().resetValues();
adVM.clearAdFilterSelections();
return true;
},
child: Column(
@ -107,7 +138,7 @@ class AdsFilterView extends StatelessWidget {
actionWidget: Builder(builder: (context) {
List<DropValue> vehicleOwnerDrop = [];
for (var element in adVM.exploreAdsEnums) {
vehicleOwnerDrop.add(DropValue(element.id.toInt(), "${element.enumValueStr} Ads", ""));
vehicleOwnerDrop.add(DropValue(element.enumValue.toInt(), "${element.enumValueStr} Ads", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleAdOwnerId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
@ -135,6 +166,7 @@ class AdsFilterView extends StatelessWidget {
maxHeight: 55,
title: LocaleKeys.search.tr(),
onPressed: () {
Navigator.pop(context);
adVM.getAdsBasedOnFilters();
},
backgroundColor: MyColors.darkPrimaryColor,
@ -148,10 +180,10 @@ class AdsFilterView extends StatelessWidget {
InkWell(
onTap: () => adVM.clearAdsFilters(),
child: LocaleKeys.clearFilters.tr().toText(
fontSize: 14,
isBold: true,
color: MyColors.darkPrimaryColor,
),
fontSize: 14,
isBold: true,
color: MyColors.darkPrimaryColor,
),
),
10.height,
],

@ -1,4 +1,5 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -6,6 +7,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -16,12 +18,12 @@ import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class CustomerAppointmentSliderWidget extends StatelessWidget {
Function(AppointmentListModel)? onAppointmentClick;
class CommonAppointmentSliderWidget extends StatelessWidget {
final Function(AppointmentListModel)? onAppointmentClick;
CustomerAppointmentSliderWidget({Key? key, this.onAppointmentClick}) : super(key: key);
const CommonAppointmentSliderWidget({Key? key, this.onAppointmentClick}) : super(key: key);
Widget getCorouselWidget(AppType appType, AppointmentsVM appointmentsVM) {
Widget getCarouselSliderWidget(AppType appType, AppointmentsVM appointmentsVM) {
return CarouselSlider.builder(
options: CarouselOptions(
height: appType == AppType.provider ? 110 : 140,
@ -52,9 +54,9 @@ class CustomerAppointmentSliderWidget extends StatelessWidget {
} else {
if (AppState().currentAppType == AppType.provider) {
if (model.myUpComingAppointments.isEmpty) {
return "No Upcoming Appointment Available".toText().paddingAll(21);
return LocaleKeys.noUpcomingAppointments.tr().toText(fontSize: 16, color: MyColors.lightTextColor).paddingAll(21);
} else {
return getCorouselWidget(AppState().currentAppType, model);
return getCarouselSliderWidget(AppState().currentAppType, model);
}
} else {
if (model.myUpComingAppointments.isEmpty) {
@ -62,16 +64,16 @@ class CustomerAppointmentSliderWidget extends StatelessWidget {
needsBorder: true,
bgColor: MyColors.white,
onTap: () => context.read<DashboardVmCustomer>().onNavbarTapped(0),
text: "Add New Appointment",
text: LocaleKeys.addNewAppointment.tr(),
icon: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).padding(EdgeInsets.symmetric(vertical: 10, horizontal: 21));
).padding(const EdgeInsets.symmetric(vertical: 10, horizontal: 21));
} else {
return getCorouselWidget(AppState().currentAppType, model);
return getCarouselSliderWidget(AppState().currentAppType, model);
}
}
}
@ -164,7 +166,7 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget {
List<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) {
if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) {
return [SizedBox()];
return [const SizedBox()];
}
if (appointmentListModel.appointmentServicesList!.length == 1) {

@ -107,15 +107,15 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
});
},
list: allMonths,
dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, ${selectedYear}", "${selectedYear}"),
dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, $selectedYear", "$selectedYear"),
hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear",
errorValue: "",
showAppointmentPickerVariant: true,
);
}),
),
Spacer(),
Icon(
const Spacer(),
const Icon(
Icons.calendar_today,
color: Colors.black,
size: 18,
@ -128,11 +128,11 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
lastDay: datesInSelectedMonth.last,
focusedDay: _focusedDay,
calendarFormat: _calendarFormat,
weekendDays: [DateTime.friday, DateTime.saturday],
weekendDays: const [DateTime.friday, DateTime.saturday],
daysOfWeekHeight: 30,
availableGestures: AvailableGestures.none,
daysOfWeekStyle: DaysOfWeekStyle(
weekdayStyle: TextStyle(fontSize: 14, color: MyColors.black),
weekdayStyle: const TextStyle(fontSize: 14, color: MyColors.black),
weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)),
),
calendarBuilders: CalendarBuilders(
@ -140,15 +140,15 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
return Container(
height: 50,
width: 50,
margin: EdgeInsets.all(5),
decoration: BoxDecoration(
margin: const EdgeInsets.all(5),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: MyColors.darkIconColor,
),
alignment: Alignment.center,
child: Text(
dateTime2.day.toString(),
style: TextStyle(color: MyColors.white),
style: const TextStyle(color: MyColors.white),
),
);
},
@ -158,7 +158,7 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
return Container(
height: 50,
width: 50,
margin: EdgeInsets.all(5),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
shape: BoxShape.circle,
@ -172,7 +172,7 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
return Container(
height: 50,
width: 50,
margin: EdgeInsets.all(5),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(color: Colors.orange, width: 2),
shape: BoxShape.circle,
@ -187,7 +187,7 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
return Container(
height: 50,
width: 50,
margin: EdgeInsets.all(5),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
shape: BoxShape.circle,
@ -199,7 +199,7 @@ class _CustomCalenderAppointmentWidgetState extends State<CustomCalenderAppointm
);
},
),
headerStyle: HeaderStyle(formatButtonVisible: false),
headerStyle: const HeaderStyle(formatButtonVisible: false),
selectedDayPredicate: (day) {
// Use `selectedDayPredicate` to determine which day is currently selected.
// If this returns true, then `day` will be marked as selected.

@ -139,6 +139,14 @@ class _ChatViewState extends State<ChatView> {
chatMessageType: ChatMessageTypeEnum.freeText,
);
} else if (chatTypeEnum == ChatTypeEnum.ads) {
status = await chatVM.onTextMessageSendForAds(
receiverId: chatViewArgumentsForAd!.receiverUserID ?? "",
chatMessageType: ChatMessageTypeEnum.freeText,
message: chatVM.chatMessageText,
adId: chatViewArgumentsForAd!.adsID!,
context: context,
);
} else if (chatTypeEnum == ChatTypeEnum.general) {
} else {}
return status;
}
@ -150,7 +158,7 @@ class _ChatViewState extends State<ChatView> {
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
List<ChatMessageModel> chatMessages = [];
if (chatTypeEnum == ChatTypeEnum.ads) {
chatMessages = chatViewArgumentsForAd!.adDetailsModel!.adMessages ?? [];
chatMessages = chatVM.currentMessagesForAds;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
if (AppState().currentAppType == AppType.customer) {
chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? [];
@ -218,15 +226,7 @@ class _ChatViewState extends State<ChatView> {
size: 30,
).onPress(
() async {
final status = await chatVM.onTextMessageSendForRequest(
context: context,
receiverId: chatViewArgumentsForRequest!.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArgumentsForRequest!.requestId ?? 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
final status = await onTextMessageSend();
if (status) {
chatVM.scrollChatDown();
chatVM.clearChatMessageText();

@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/ads_list.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class AdsFragment extends StatelessWidget {
const AdsFragment({Key? key}) : super(key: key);
List<AdDetailsModel> getAdsList(AdVM adVM) {
if (adVM.isExploreAdsTapped) {
return adVM.exploreAdsFilteredList;
}
if (adVM.myAdsFilteredList.isNotEmpty) {
return adVM.myAdsFilteredList;
}
return [];
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.ads.tr(),
isRemoveBackButton: true,
actions: [
Padding(
padding: EdgeInsets.only(top: adVM.adsFiltersCounter > 0 ? 20 : 0, right: 21),
child: Badge(
isLabelVisible: adVM.adsFiltersCounter > 0,
largeSize: 15,
smallSize: 20,
backgroundColor: MyColors.darkPrimaryColor,
label: Text('${adVM.adsFiltersCounter}'),
child: MyAssets.searchIcon.buildSvg(),
),
).onPress(() {
navigateWithName(context, AppRoutes.adsFilterView);
})
],
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
children: [
16.height,
Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
children: [
Row(
children: [
Expanded(
child: ShowFillButton(
isFilled: adVM.isExploreAdsTapped,
maxHeight: 55,
title: LocaleKeys.exploreAds.tr(),
txtColor: adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor,
onPressed: () {
print("accessToken: ${AppState().getUser.data!.accessToken}");
adVM.populateAdsFilterList();
if (adVM.myAds.isEmpty) {
adVM.getMyAds();
}
adVM.updateIsExploreAds(true);
},
),
),
12.width,
Expanded(
child: ShowFillButton(
isFilled: !adVM.isExploreAdsTapped,
txtColor: !adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor,
maxHeight: 55,
title: LocaleKeys.myAds.tr(),
onPressed: () {
adVM.updateIsExploreAds(false);
},
),
),
],
).horPaddingMain(),
if (adVM.isExploreAdsTapped) ...[
if (adVM.adsFiltersCounter == 0) ...[
16.height,
FiltersList(
filterList: adVM.exploreAdsFilterOptions,
onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnExploreAds(createdByRoleFilter: selectedFilterId.toCreatedByRoleEnum()),
needLeftPadding: false)
.paddingOnly(left: 21),
]
] else ...[
16.height,
FiltersList(
filterList: adVM.myAdsFilterOptions,
onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnMyAds(adPostStatusEnum: selectedFilterId.toAdPostEnum()),
needLeftPadding: false,
).paddingOnly(left: 21),
],
],
);
},
),
16.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async {
await adVM.getExploreAds();
await adVM.getMyAds();
},
child: BuildAdsList(isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM)),
),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
navigateWithName(context, AppRoutes.selectAdTypeView, arguments: injector.get<AppState>().currentAppType == AppType.provider);
},
backgroundColor: MyColors.darkPrimaryColor,
child: const Icon(Icons.add, color: MyColors.white),
),
);
},
);
}
}

@ -0,0 +1,81 @@
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/requests/widget/request_item.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class MyRequestsFragment extends StatelessWidget {
const MyRequestsFragment({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.myRequests.tr(),
isRemoveBackButton: true,
),
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Column(
children: [
16.height,
FiltersList(
filterList: requestsVM.requestsTypeFilterOptions,
onFilterTapped: (index, selectedFilterId) {
requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: selectedFilterId.toRequestTypeStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true, appType: AppType.provider),
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.separated(
itemBuilder: (context, index) {
return RequestItem(request: requestsVM.myFilteredRequests[index], appType: AppType.provider, requestIndex: index);
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: requestsVM.myFilteredRequests.length,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
),
))
],
);
}),
),
floatingActionButton: AppState().currentAppType == AppType.customer
? FloatingActionButton(
onPressed: () => navigateWithName(context, AppRoutes.createRequestPage),
backgroundColor: MyColors.darkPrimaryColor,
child: const Icon(
Icons.add,
color: MyColors.white,
),
)
: null,
);
}
}

@ -49,7 +49,7 @@ class RequestItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (request.offerCount > 0) ...[
if (request.offerCount > 0 && appType == AppType.customer) ...[
Center(
child: "${request.offerCount}".toText(
color: Colors.white,

@ -1,47 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class ServiceProviderWidget extends StatelessWidget {
final List<BranchDetailModel> nearbyBranches;
const ServiceProviderWidget({Key? key, required this.nearbyBranches}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 140,
child: ListView.builder(
itemCount: nearbyBranches.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
BranchDetailModel branchDetailModel = nearbyBranches[index];
return SizedBox(
width: 90,
child: Column(
children: [
Image.asset(
MyAssets.bnCar,
width: 80,
height: 80,
fit: BoxFit.cover,
).toCircle(borderRadius: 100),
8.height,
"${branchDetailModel.branchName}".toText(fontSize: 14, isBold: true, textAlign: TextAlign.center),
],
),
).onPress(() {
navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel);
});
},
),
);
}
}

@ -1,119 +0,0 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class ProviderAppointmentSliderWidget extends StatelessWidget {
const ProviderAppointmentSliderWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CarouselSlider.builder(
options: CarouselOptions(
height: 160,
viewportFraction: 1.0,
enlargeCenterPage: false,
enableInfiniteScroll: false,
//
// onPageChanged: (index) {
// setState(() {
// _current = index;
// });
// },
),
itemCount: 10,
itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => const BuildAppointmentContainerForProvider(),
);
}
}
class BuildAppointmentContainerForProvider extends StatelessWidget {
const BuildAppointmentContainerForProvider({Key? key}) : super(key: key);
Widget showServices(String title, String icon) {
return Row(
children: [
SvgPicture.asset(icon),
8.width,
title.toText(
fontSize: 14,
isBold: true,
),
],
);
}
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 21, left: 21, right: 21, top: 7),
child: Column(
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Olaya Brach".toText(
color: MyColors.lightTextColor,
isBold: true,
),
"Abdullah Alhbas".toText(
isBold: true,
fontSize: 14,
),
Row(
children: [
"Appt. On:".toText(
color: MyColors.lightTextColor,
),
2.width,
"19-Mar-2023 11:48 AM".toText(),
],
),
],
),
),
"1+ Requests".toText(fontSize: 10).toContainer(
borderRadius: 15,
backgroundColor: MyColors.lightGreyEAColor,
padding: const EdgeInsets.symmetric(
vertical: 6,
horizontal: 12,
),
),
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Column(
children: [
showServices("Maintenance", MyAssets.maintenanceIcon ),
2.height,
showServices("Accessories and Modification", MyAssets.modificationsIcon,),
],
),
),
const Icon(
Icons.arrow_forward,
),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
);
}
}
Loading…
Cancel
Save