Merge branch 'faiz_development_common' into master_new_changes

# Conflicts:
#	lib/classes/app_state.dart
#	lib/services/payments_service.dart
#	lib/view_models/payment_view_model.dart
#	lib/view_models/service_view_model.dart
#	lib/views/setting_options/setting_options_more.dart
#	lib/views/user/login_with_password_page.dart
master_new_changes
Aamir 1 year ago
commit 8d9c4091fb

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -579,7 +579,7 @@
"requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.", "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.",
"acceptOfferConfirmation": "هل تريد قبول هذا العرض؟", "acceptOfferConfirmation": "هل تريد قبول هذا العرض؟",
"acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض.", "acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض.",
"noUpcomingAppointments": "لا يوجد موعد قادم متاح", "noUpcomingAppointments": "لا مواعيد قادم..",
"addNewAppointment": "إضافة موعد جديد", "addNewAppointment": "إضافة موعد جديد",
"myNearbyBranches": "فروعي القريبة", "myNearbyBranches": "فروعي القريبة",
"myRecentBranches": "فروعي الأخيرة", "myRecentBranches": "فروعي الأخيرة",
@ -654,5 +654,30 @@
"date": "التاريخ", "date": "التاريخ",
"selectAll": "اختر الكل", "selectAll": "اختر الكل",
"unselectAll": "إلغاء اختيار الكل", "unselectAll": "إلغاء اختيار الكل",
"copySelectedServices": "نسخ الخدمات المحددة" "copySelectedServices": "نسخ الخدمات المحددة",
"pictures": "الصور",
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!",
"shippingManagement": "إدارة الشحن",
"appointmentCancelled": "تم إلغاء الموعد",
"appointmentsPerSlot": "المواعيد لكل فترة زمنية",
"createSchedule": "إنشاء الجدول الزمني",
"addItems": "إضافة عناصر",
"itemName": "اسم العنصر",
"itemDescription": "وصف العنصر",
"itemPrice": "سعر العنصر",
"bookAppointmentForServices": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"showServiceAvailability": "سيظهر هذا الخيار للعميل ما إذا كان بإمكانه الحصول على هذه الخدمة في الورشة أم لا.",
"bookAppointmentAtLocation": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يرغب فيه.",
"appointmentBookingOption": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"workshopAvailabilityOption": "سيظهر هذا الخيار للعميل إذا كان يمكنه الحصول على هذه الخدمة في الورشة أم لا.",
"appointmentLocationOption": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يختاره.",
"deleteScheduleConfirmation": "هل أنت متأكد أنك تريد حذف هذا الجدول؟",
"deleteScheduleAdConfirmationMessage": "سيتم إزالة جميع فترات المواعيد ولن يتمكن العملاء من حجز مواعيد لهذا الجدول.",
"branchSchedules": "جداول الفرع",
"noSchedulesFound": "لم تقم بإضافة أي جدول لهذا الفرع.",
"inviteFriendsBySMS": "دعوة الأصدقاء عبر الرسائل القصيرة",
"inviteFriendsByWhatsApp": "دعوة الأصدقاء عبر واتساب",
"inviteFriendsByEmail": "دعوة الأصدقاء عبر البريد الإلكتروني",
"noFAQsToShow": "لا توجد أسئلة شائعة في الوقت الحالي. يرجى الاتصال بنا إذا كان لديك أي استفسار.",
"appInfo": "معلومات التطبيق"
} }

@ -580,7 +580,7 @@
"upgradeVar": "Upgrade", "upgradeVar": "Upgrade",
"whendoyouWanttoRenew": "When do you want to renew", "whendoyouWanttoRenew": "When do you want to renew",
"renewVar": "Renew", "renewVar": "Renew",
"noUpcomingAppointments": "No Upcoming Appointment Available.", "noUpcomingAppointments": "No Upcoming Appointments.",
"addNewAppointment": "Add New Appointment", "addNewAppointment": "Add New Appointment",
"myNearbyBranches": "My Nearby Branches", "myNearbyBranches": "My Nearby Branches",
"myRecentBranches": "My Recent Branches", "myRecentBranches": "My Recent Branches",
@ -655,5 +655,27 @@
"date": "Date", "date": "Date",
"selectAll": "Select All", "selectAll": "Select All",
"unselectAll": "Unselect All", "unselectAll": "Unselect All",
"copySelectedServices": "Copy Selected Services" "copySelectedServices": "Copy Selected Services",
"pictures": "Pictures",
"noChatMessage": "No messages yet. Send a message to start the conversation!",
"shippingManagement": "Shipping Management",
"appointmentCancelled": "Appointment Cancelled",
"appointmentsPerSlot": "Appointments Per Slot",
"createSchedule": "Create Schedule",
"addItems": "Add Items",
"itemName": "Item Name",
"itemDescription": "Item Description",
"itemPrice": "Item Price",
"bookAppointmentForServices": "This option will allow customer to book appointment for these services.",
"showServiceAvailability": "This option will show to customer that you can avail this service on workshop or not.",
"bookAppointmentAtLocation": "This option will allow customer to book appointment at their desired location.",
"deleteScheduleConfirmation": " Are you sure you want to delete this Schedule?",
"deleteScheduleAdConfirmationMessage": "All the appointment slots will be removed and customers will no longer be able to book appointments for this schedule.",
"branchSchedules": "Branch Schedules",
"noSchedulesFound": "You have not added any schedule for this branch.",
"inviteFriendsBySMS": "Invite Friends By SMS",
"inviteFriendsByWhatsApp": "Invite Friends By WhatsApp",
"inviteFriendsByEmail": "Invite Friends By Email",
"noFAQsToShow": "There are no Frequently asked Questions Right now. Please contact us if you have any query.",
"appInfo": "App Info"
} }

@ -65,7 +65,7 @@ class AppState {
List<Subscription>? _providerSubscription; List<Subscription>? _providerSubscription;
List<Subscription> get getproviderSubscription => _providerSubscription ?? [new Subscription(name: "")]; List<Subscription> get getproviderSubscription => _providerSubscription ?? [Subscription(name: "")];
set setproviderSubscription(List<Subscription> value) { set setproviderSubscription(List<Subscription> value) {
_providerSubscription = value; _providerSubscription = value;

@ -136,6 +136,7 @@ class ApiConsts {
// Payment // Payment
static String paymentWebViewUrl = "https://ms.hmg.com/pay/PaymentHome"; static String paymentWebViewUrl = "https://ms.hmg.com/pay/PaymentHome";
static String payForOrderDetailGet = "${baseUrlServices}api/Payment/PayFortOrderDetail_Get"; static String payForOrderDetailGet = "${baseUrlServices}api/Payment/PayFortOrderDetail_Get";
static String payForOrderIsPaidGet = "${baseUrlServices}api/Payment/PayFortOrderIsPaid_Get";
//Duplicate Services //Duplicate Services
static String getMatchedServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderBranchServicesMapping_Get"; static String getMatchedServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderBranchServicesMapping_Get";
@ -144,8 +145,6 @@ class ApiConsts {
//Branch Users //Branch Users
static String getAllProviderDealers = "${baseUrlServices}api/ServiceProviders/DealershipUserBranchWise_Get"; static String getAllProviderDealers = "${baseUrlServices}api/ServiceProviders/DealershipUserBranchWise_Get";
// /api/ServiceProviders/BranchUser_Get
//DealershipUserBranchWise_Get
static String getBranchUser = "${baseUrlServices}api/ServiceProviders/BranchUser_Get"; static String getBranchUser = "${baseUrlServices}api/ServiceProviders/BranchUser_Get";
static String assignDealerToBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Create"; static String assignDealerToBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Create";
static String removeDealerFromBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Update"; static String removeDealerFromBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Update";
@ -163,6 +162,10 @@ class ApiConsts {
static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get"; static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get";
static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider"; static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider";
//Shipping
static String shippingRequestStatusUpdate = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Update";
static String shippingRequestStatusGet = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Get";
//Chat //Chat
static String chatHubUrl = "$baseUrlServices/McHub"; static String chatHubUrl = "$baseUrlServices/McHub";
static String messageIsReadUpdateForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update"; static String messageIsReadUpdateForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update";
@ -171,6 +174,12 @@ class ApiConsts {
static String getChatMessagesForAds = "${baseUrlServices}api/Advertisement/AdsChat_Get"; static String getChatMessagesForAds = "${baseUrlServices}api/Advertisement/AdsChat_Get";
static String getChatBuyersForAds = "${baseUrlServices}api/Advertisement/AdsChatBuyer_Get"; static String getChatBuyersForAds = "${baseUrlServices}api/Advertisement/AdsChatBuyer_Get";
//Settings Options
static String getAllFAQs = "${baseUrlServices}api/Common/FAQ_Get";
static String getAppInvitationLink = "${baseUrlServices}api/Common/AppInvitation_Get";
static String getContactInfo = "${baseUrlServices}api/Master/ContactInfo_Get";
static String getAppInfo = "${baseUrlServices}api/Master/AppInfo_Get";
static List<String> closingUrls = ["PayFortResponse"]; static List<String> closingUrls = ["PayFortResponse"];
} }
@ -292,6 +301,7 @@ class MyAssets {
static String whatsAppIcon = "${assetPath}icons/whatsapp_icon.svg"; static String whatsAppIcon = "${assetPath}icons/whatsapp_icon.svg";
static const String arrowRight = "${assetPath}icons/ic_arrow_right.svg"; static const String arrowRight = "${assetPath}icons/ic_arrow_right.svg";
static const String brokenImage = "${assetPath}images/broken_image.png";
} }
RegExp numReg = RegExp(r".*[0-9].*"); RegExp numReg = RegExp(r".*[0-9].*");

@ -12,6 +12,8 @@ import 'package:mc_common_app/repositories/branch_repo.dart';
import 'package:mc_common_app/repositories/chat_repo.dart'; import 'package:mc_common_app/repositories/chat_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/payments_repo.dart'; import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/repositories/setting_options_repo.dart';
import 'package:mc_common_app/repositories/shipping_repo.dart';
import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart'; import 'package:mc_common_app/services/firebase_service.dart';
@ -42,6 +44,8 @@ class AppDependencies {
injector.registerSingleton<AppointmentRepo>(() => AppointmentRepoImp()); injector.registerSingleton<AppointmentRepo>(() => AppointmentRepoImp());
injector.registerSingleton<ChatRepo>(() => ChatRepoImp()); injector.registerSingleton<ChatRepo>(() => ChatRepoImp());
injector.registerSingleton<BranchRepo>(() => BranchRepoImp()); injector.registerSingleton<BranchRepo>(() => BranchRepoImp());
injector.registerSingleton<ShippingRepo>(() => ShippingRepoImp());
injector.registerSingleton<SettingOptionsRepo>(() => SettingOptionsRepoImp());
// //
} }

@ -1,5 +1,6 @@
import 'package:mc_common_app/models/advertisment_models/ad_details_model.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/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/requests_models/provider_offers_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/requests_models/request_model.dart';
import 'package:mc_common_app/models/user_models/register_user.dart'; import 'package:mc_common_app/models/user_models/register_user.dart';
@ -19,9 +20,12 @@ import 'package:mc_common_app/views/requests/requests_filter_view.dart';
import 'package:mc_common_app/views/requests/review_request_offer.dart'; import 'package:mc_common_app/views/requests/review_request_offer.dart';
import 'package:mc_common_app/views/setting_options/provider_license_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_option_help.dart';
import 'package:mc_common_app/views/setting_options/setting_options_app_info.dart';
import 'package:mc_common_app/views/setting_options/setting_options_contact_us.dart';
import 'package:mc_common_app/views/setting_options/setting_options_faqs.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_invite_friends.dart';
import 'package:mc_common_app/views/setting_options/setting_options_language.dart'; import 'package:mc_common_app/views/setting_options/setting_options_more.dart';
import 'package:mc_common_app/views/shipping_management/shipping_management_view.dart';
import 'package:mc_common_app/views/user/change_email_page.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_mobile_page.dart';
import 'package:mc_common_app/views/user/change_password_page.dart'; import 'package:mc_common_app/views/user/change_password_page.dart';
@ -40,6 +44,7 @@ import 'package:mc_common_app/views/user/register_selection_page.dart';
import 'package:mc_common_app/views/splash/splash_page.dart'; import 'package:mc_common_app/views/splash/splash_page.dart';
import 'package:mc_common_app/views/user/vertify_password_page.dart'; import 'package:mc_common_app/views/user/vertify_password_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/widgets/image_viewer/image_viewer_screen.dart';
class AppRoutes { class AppRoutes {
//User //User
@ -67,7 +72,7 @@ class AppRoutes {
static const String dashboard = "/dashboard"; static const String dashboard = "/dashboard";
static const String bookProviderAppView = "/bookProviderAppView"; static const String bookProviderAppView = "/bookProviderAppView";
// Appoinments // Appointments
static const String appointmentDetailView = "/appointmentDetailView"; static const String appointmentDetailView = "/appointmentDetailView";
static const String bookAppointmenServicesView = "/bookAppointmenServicesView"; static const String bookAppointmenServicesView = "/bookAppointmenServicesView";
static const String bookAppointmenSchedulesView = "/bookAppointmenSchedulesView"; static const String bookAppointmenSchedulesView = "/bookAppointmenSchedulesView";
@ -85,6 +90,10 @@ class AppRoutes {
// Payments // Payments
static const String paymentMethodsView = "/paymentMethodsView"; static const String paymentMethodsView = "/paymentMethodsView";
//Shipping
static const shippingManagementView = "/shippingManagementView";
//Customer APP: Provider & Services //Customer APP: Provider & Services
static const String branchDetailView = "/branchDetailPage"; static const String branchDetailView = "/branchDetailPage";
static const String branchSearchFilterPage = "/branchSearchFilterPage"; static const String branchSearchFilterPage = "/branchSearchFilterPage";
@ -106,10 +115,15 @@ class AppRoutes {
//Setting Options //Setting Options
static const String settingOptionsFaqs = "/settingOptionsFaqs"; static const String settingOptionsFaqs = "/settingOptionsFaqs";
static const String settingOptionsLanguages = "/settingOptionsLanguages"; static const String settingOptionsContactUs = "/settingOptionsContactUs";
static const String settingOptionsAppInfo = "/settingOptionsAppInfo";
static const String settingOptionsMore = "/settingOptionsLanguages";
static const String settingOptionsInviteFriends = "/settingOptionsInviteFriends"; static const String settingOptionsInviteFriends = "/settingOptionsInviteFriends";
static const String settingOptionsHelp = "/settingOptionsHelp"; static const String settingOptionsHelp = "/settingOptionsHelp";
//MediaViewer
static const String mediaViewerScreen = "/mediaViewer";
//Profile Screen //Profile Screen
static const String profileView = "/profileView"; static const String profileView = "/profileView";
@ -118,9 +132,12 @@ class AppRoutes {
//Provider User Page //Provider User Page
static const dealerUser = "/dealerUser"; static const dealerUser = "/dealerUser";
// HomePage Provider
static const String generalChatsListForProvider = "/generalChatsListForProvider";
//Chat //Chat
static const String chatView = "/chatView"; static const String chatView = "/chatView";
static const String initialRoute = splash; static const String initialRoute = splash;
static final Map<String, WidgetBuilder> routes = { static final Map<String, WidgetBuilder> routes = {
@ -137,13 +154,13 @@ class AppRoutes {
completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUserRespModel), completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUserRespModel),
verifyPassword: (context) => VerifyPasswordPage(), 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(), changeMobilePage: (context) => ChangeMobilePage(),
changeEmailPage: (context) => const ChangeEmailPage(), changeEmailPage: (context) => const ChangeEmailPage(),
changePassword: (context) => const ChangePasswordPage(),
editAccountPage: (context) => const EditAccountPage(), editAccountPage: (context) => const EditAccountPage(),
profileView: (context) => const ProfileScreen(), profileView: (context) => const ProfileScreen(),
settingOptionsLanguages: (context) => const SettingOptionsLanguage(), settingOptionsMore: (context) => const SettingOptionsMore(),
settingOptionsHelp: (context) => const SettingOptionsHelp(), settingOptionsHelp: (context) => const SettingOptionsHelp(),
providerLicensePage: (context) => const ProviderLicensePage(), providerLicensePage: (context) => const ProviderLicensePage(),
@ -151,10 +168,12 @@ class AppRoutes {
AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel), AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
AppRoutes.createAdView: (context) => const CreateAdView(), AppRoutes.createAdView: (context) => const CreateAdView(),
AppRoutes.adsFilterView: (context) => const AdsFilterView(), AppRoutes.adsFilterView: (context) => const AdsFilterView(),
AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(arguments: ModalRoute.of(context)!.settings.arguments as List<bool>), AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(arguments: ModalRoute.of(context)!.settings.arguments as List<dynamic>),
AppRoutes.chatView: (context) => ChatView(chatViewArguments: ModalRoute.of(context)!.settings.arguments as ChatViewArguments), AppRoutes.chatView: (context) => ChatView(chatViewArguments: ModalRoute.of(context)!.settings.arguments as ChatViewArguments),
AppRoutes.adsBuyerChatsListView: (context) => AdsBuyerChatsView(buyersListViewArguments: ModalRoute.of(context)!.settings.arguments as List<BuyersChatForAdsModel>), AppRoutes.adsBuyerChatsListView: (context) => AdsBuyerChatsView(buyersListViewArguments: ModalRoute.of(context)!.settings.arguments as List<BuyersChatForAdsModel>),
AppRoutes.settingOptionsFaqs: (context) => const SettingOptionsFAQs(), AppRoutes.settingOptionsFaqs: (context) => const SettingOptionsFAQs(),
AppRoutes.settingOptionsContactUs: (context) => const SettingOptionsContactUs(),
AppRoutes.settingOptionsAppInfo: (context) => const SettingOptionsAppInfo(),
AppRoutes.settingOptionsInviteFriends: (context) => const SettingOptionsInviteFriends(), AppRoutes.settingOptionsInviteFriends: (context) => const SettingOptionsInviteFriends(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes),
//Requests //Requests
@ -163,6 +182,15 @@ class AppRoutes {
AppRoutes.offersListPage: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments), AppRoutes.offersListPage: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments),
AppRoutes.reviewRequestOffer: (context) => const ReviewRequestOffer(), AppRoutes.reviewRequestOffer: (context) => const ReviewRequestOffer(),
AppRoutes.requestsFilterView: (context) => const RequestsFilterView(), AppRoutes.requestsFilterView: (context) => const RequestsFilterView(),
//MediaViewer
AppRoutes.mediaViewerScreen: (context) => MediaViewerScreen(images: ModalRoute.of(context)!.settings.arguments as List<MessageImageModel>),
// ChatsList Provider
AppRoutes.generalChatsListForProvider: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments),
//Shipping
AppRoutes.shippingManagementView: (context) => const ShippingManagementView(),
}; };
} }

@ -3,7 +3,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
@ -283,6 +282,31 @@ extension AppointmentStatusToInt on AppointmentStatusEnum {
} }
} }
extension AppointmentTypeEnumExt on int {
AppointmentTypeEnum toAppointmentTypeEnum() {
if (this == 1) {
return AppointmentTypeEnum.workshop;
} else if (this == 2) {
return AppointmentTypeEnum.home;
} else {
return AppointmentTypeEnum.workshop;
}
}
}
extension AppointmentTypeEnumExtString on AppointmentTypeEnum {
int getIdFromAppointmentTypeEnum() {
switch (this) {
case AppointmentTypeEnum.workshop:
return 1;
case AppointmentTypeEnum.home:
return 2;
default:
return 1;
}
}
}
extension AppointmentStatusToString on AppointmentStatusEnum { extension AppointmentStatusToString on AppointmentStatusEnum {
String getAppointmentNameFromEnum() { String getAppointmentNameFromEnum() {
switch (this) { switch (this) {
@ -455,16 +479,12 @@ extension PaymentTypesToInt on PaymentTypes {
switch (this) { switch (this) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
return 1; return 1;
case PaymentTypes.appointment: case PaymentTypes.appointment:
return 2; return 2;
case PaymentTypes.adReserve: case PaymentTypes.adReserve:
return 4; return 4;
case PaymentTypes.ads: case PaymentTypes.ads:
return 3; return 3;
case PaymentTypes.request: case PaymentTypes.request:
return 5; return 5;
case PaymentTypes.extendAds: case PaymentTypes.extendAds:
@ -478,6 +498,30 @@ extension PaymentTypesToInt on PaymentTypes {
} }
} }
extension PaymentIdToPaymentTypes on int {
PaymentTypes getPaymentTypeFromId() {
switch (this) {
case 1:
return PaymentTypes.subscription;
case 2:
return PaymentTypes.appointment;
case 4:
return PaymentTypes.adReserve;
case 3:
return PaymentTypes.ads;
case 5:
return PaymentTypes.request;
case 6:
return PaymentTypes.extendAds;
case 7:
return PaymentTypes.partialAppointment;
default:
return PaymentTypes.ads;
}
}
}
extension CreatedByRoleEnumToInt on CreatedByRoleEnum { extension CreatedByRoleEnumToInt on CreatedByRoleEnum {
int getIdFromCreatedByRoleEnum() { int getIdFromCreatedByRoleEnum() {
switch (this) { switch (this) {
@ -577,7 +621,7 @@ extension DateTimeConversions on DateTime {
final date2 = DateTime.now(); final date2 = DateTime.now();
final difference = date2.difference(this); final difference = date2.difference(this);
if ((difference.inDays / 7).floor() >= 2) { if ((difference.inDays / 7).floor() >= 2) {
return DateHelper.formatAsDayMonthYear(date2); return DateHelper.formatAsDayMonthYear(this);
} else if ((difference.inDays / 7).floor() >= 1) { } else if ((difference.inDays / 7).floor() >= 1) {
return (numericDates) ? '1 week ago' : 'Last week'; return (numericDates) ? '1 week ago' : 'Last week';
} else if (difference.inDays >= 2) { } else if (difference.inDays >= 2) {
@ -863,3 +907,38 @@ extension SubscriptionTypeEnumToString on SubscriptionTypeEnum {
} }
} }
} }
extension ShippingStatusEnumExt on int {
ShippingRequestStatusEnum toShippingStatusEnum() {
if (this == 0) {
return ShippingRequestStatusEnum.allRequests;
} else if (this == 1) {
return ShippingRequestStatusEnum.initiated;
} else if (this == 2) {
return ShippingRequestStatusEnum.inTransit;
} else if (this == 3) {
return ShippingRequestStatusEnum.outForDelivery;
} else if (this == 4) {
return ShippingRequestStatusEnum.delivered;
}
return ShippingRequestStatusEnum.initiated;
}
}
extension ShippingStatusEnumToInt on ShippingRequestStatusEnum {
int getIdFromShippingStatusEnum() {
switch (this) {
case ShippingRequestStatusEnum.initiated:
return 1;
case ShippingRequestStatusEnum.inTransit:
return 2;
case ShippingRequestStatusEnum.outForDelivery:
return 3;
case ShippingRequestStatusEnum.delivered:
return 4;
default:
return 0;
}
}
}

@ -595,7 +595,7 @@ class CodegenLoader extends AssetLoader{
"requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.", "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.",
"acceptOfferConfirmation": "هل تريد قبول هذا العرض؟", "acceptOfferConfirmation": "هل تريد قبول هذا العرض؟",
"acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض.", "acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض.",
"noUpcomingAppointments": "لا يوجد موعد قادم متاح", "noUpcomingAppointments": "لا مواعيد قادم..",
"addNewAppointment": "إضافة موعد جديد", "addNewAppointment": "إضافة موعد جديد",
"myNearbyBranches": "فروعي القريبة", "myNearbyBranches": "فروعي القريبة",
"myRecentBranches": "فروعي الأخيرة", "myRecentBranches": "فروعي الأخيرة",
@ -670,7 +670,32 @@ class CodegenLoader extends AssetLoader{
"date": "التاريخ", "date": "التاريخ",
"selectAll": "اختر الكل", "selectAll": "اختر الكل",
"unselectAll": "إلغاء اختيار الكل", "unselectAll": "إلغاء اختيار الكل",
"copySelectedServices": "نسخ الخدمات المحددة" "copySelectedServices": "نسخ الخدمات المحددة",
"pictures": "الصور",
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!",
"shippingManagement": "إدارة الشحن",
"appointmentCancelled": "تم إلغاء الموعد",
"appointmentsPerSlot": "المواعيد لكل فترة زمنية",
"createSchedule": "إنشاء الجدول الزمني",
"addItems": "إضافة عناصر",
"itemName": "اسم العنصر",
"itemDescription": "وصف العنصر",
"itemPrice": "سعر العنصر",
"bookAppointmentForServices": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"showServiceAvailability": "سيظهر هذا الخيار للعميل ما إذا كان بإمكانه الحصول على هذه الخدمة في الورشة أم لا.",
"bookAppointmentAtLocation": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يرغب فيه.",
"appointmentBookingOption": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"workshopAvailabilityOption": "سيظهر هذا الخيار للعميل إذا كان يمكنه الحصول على هذه الخدمة في الورشة أم لا.",
"appointmentLocationOption": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يختاره.",
"deleteScheduleConfirmation": "هل أنت متأكد أنك تريد حذف هذا الجدول؟",
"deleteScheduleAdConfirmationMessage": "سيتم إزالة جميع فترات المواعيد ولن يتمكن العملاء من حجز مواعيد لهذا الجدول.",
"branchSchedules": "جداول الفرع",
"noSchedulesFound": "لم تقم بإضافة أي جدول لهذا الفرع.",
"inviteFriendsBySMS": "دعوة الأصدقاء عبر الرسائل القصيرة",
"inviteFriendsByWhatsApp": "دعوة الأصدقاء عبر واتساب",
"inviteFriendsByEmail": "دعوة الأصدقاء عبر البريد الإلكتروني",
"noFAQsToShow": "لا توجد أسئلة شائعة في الوقت الحالي. يرجى الاتصال بنا إذا كان لديك أي استفسار.",
"appInfo": "معلومات التطبيق"
}; };
static const Map<String,dynamic> en_US = { static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In", "firstTimeLogIn": "First Time Log In",
@ -1254,7 +1279,7 @@ static const Map<String,dynamic> en_US = {
"upgradeVar": "Upgrade", "upgradeVar": "Upgrade",
"whendoyouWanttoRenew": "When do you want to renew", "whendoyouWanttoRenew": "When do you want to renew",
"renewVar": "Renew", "renewVar": "Renew",
"noUpcomingAppointments": "No Upcoming Appointment Available.", "noUpcomingAppointments": "No Upcoming Appointments.",
"addNewAppointment": "Add New Appointment", "addNewAppointment": "Add New Appointment",
"myNearbyBranches": "My Nearby Branches", "myNearbyBranches": "My Nearby Branches",
"myRecentBranches": "My Recent Branches", "myRecentBranches": "My Recent Branches",
@ -1329,7 +1354,29 @@ static const Map<String,dynamic> en_US = {
"date": "Date", "date": "Date",
"selectAll": "Select All", "selectAll": "Select All",
"unselectAll": "Unselect All", "unselectAll": "Unselect All",
"copySelectedServices": "Copy Selected Services" "copySelectedServices": "Copy Selected Services",
"pictures": "Pictures",
"noChatMessage": "No messages yet. Send a message to start the conversation!",
"shippingManagement": "Shipping Management",
"appointmentCancelled": "Appointment Cancelled",
"appointmentsPerSlot": "Appointments Per Slot",
"createSchedule": "Create Schedule",
"addItems": "Add Items",
"itemName": "Item Name",
"itemDescription": "Item Description",
"itemPrice": "Item Price",
"bookAppointmentForServices": "This option will allow customer to book appointment for these services.",
"showServiceAvailability": "This option will show to customer that you can avail this service on workshop or not.",
"bookAppointmentAtLocation": "This option will allow customer to book appointment at their desired location.",
"deleteScheduleConfirmation": " Are you sure you want to delete this Schedule?",
"deleteScheduleAdConfirmationMessage": "All the appointment slots will be removed and customers will no longer be able to book appointments for this schedule.",
"branchSchedules": "Branch Schedules",
"noSchedulesFound": "You have not added any schedule for this branch.",
"inviteFriendsBySMS": "Invite Friends By SMS",
"inviteFriendsByWhatsApp": "Invite Friends By WhatsApp",
"inviteFriendsByEmail": "Invite Friends By Email",
"noFAQsToShow": "There are no Frequently asked Questions Right now. Please contact us if you have any query.",
"appInfo": "App Info"
}; };
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
} }

@ -634,5 +634,30 @@ abstract class LocaleKeys {
static const selectAll = 'selectAll'; static const selectAll = 'selectAll';
static const unselectAll = 'unselectAll'; static const unselectAll = 'unselectAll';
static const copySelectedServices = 'copySelectedServices'; static const copySelectedServices = 'copySelectedServices';
static const pictures = 'pictures';
static const noChatMessage = 'noChatMessage';
static const shippingManagement = 'shippingManagement';
static const appointmentCancelled = 'appointmentCancelled';
static const appointmentsPerSlot = 'appointmentsPerSlot';
static const createSchedule = 'createSchedule';
static const addItems = 'addItems';
static const itemName = 'itemName';
static const itemDescription = 'itemDescription';
static const itemPrice = 'itemPrice';
static const bookAppointmentForServices = 'bookAppointmentForServices';
static const showServiceAvailability = 'showServiceAvailability';
static const bookAppointmentAtLocation = 'bookAppointmentAtLocation';
static const appointmentBookingOption = 'appointmentBookingOption';
static const workshopAvailabilityOption = 'workshopAvailabilityOption';
static const appointmentLocationOption = 'appointmentLocationOption';
static const deleteScheduleConfirmation = 'deleteScheduleConfirmation';
static const deleteScheduleAdConfirmationMessage = 'deleteScheduleAdConfirmationMessage';
static const branchSchedules = 'branchSchedules';
static const noSchedulesFound = 'noSchedulesFound';
static const inviteFriendsBySMS = 'inviteFriendsBySMS';
static const inviteFriendsByWhatsApp = 'inviteFriendsByWhatsApp';
static const inviteFriendsByEmail = 'inviteFriendsByEmail';
static const noFAQsToShow = 'noFAQsToShow';
static const appInfo = 'appInfo';
} }

@ -2,6 +2,9 @@ import 'package:logger/logger.dart';
Logger logger = Logger(printer: PrettyPrinter(printEmojis: false, colors: true, printTime: false)); Logger logger = Logger(printer: PrettyPrinter(printEmojis: false, colors: true, printTime: false));
bool disableThingsForQA = true;
// Language Tile in Settings
// todo terminal command to genertate translation files // todo terminal command to genertate translation files
// flutter pub run easy_localization:generate --source-dir ./assets/langs // flutter pub run easy_localization:generate --source-dir ./assets/langs

@ -16,6 +16,8 @@ class AppointmentListModel {
String? customerName; String? customerName;
String? customerMobileNum; String? customerMobileNum;
int? appointmentType; int? appointmentType;
AppointmentTypeEnum? appointmentTypeEnum;
String? providerName; String? providerName;
String? duration; String? duration;
String? appointmentDate; String? appointmentDate;
@ -45,6 +47,7 @@ class AppointmentListModel {
this.customerName, this.customerName,
this.customerMobileNum, this.customerMobileNum,
this.appointmentType, this.appointmentType,
this.appointmentTypeEnum,
this.providerName, this.providerName,
this.duration, this.duration,
this.branchName, this.branchName,
@ -76,6 +79,7 @@ class AppointmentListModel {
customerName = json['customerName']; customerName = json['customerName'];
customerMobileNum = json['customerMobile']; customerMobileNum = json['customerMobile'];
appointmentType = json['appointmentType']; appointmentType = json['appointmentType'];
appointmentTypeEnum = json['appointmentType'] != null ? (json['appointmentType'] as int).toAppointmentTypeEnum() : AppointmentTypeEnum.workshop;
providerName = json['providerName']; providerName = json['providerName'];
duration = json['duration']; duration = json['duration'];
appointmentDate = json['appointmentDate']; appointmentDate = json['appointmentDate'];

@ -1,6 +1,7 @@
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/utils/enums.dart';
class CustomTimeDateSlotModel { class CustomTimeDateSlotModel {
TimeSlotModel? date; TimeSlotModel? date;
@ -19,6 +20,7 @@ class ServiceAppointmentScheduleModel {
double? amountTotal; double? amountTotal;
double? amountRem; double? amountRem;
int? appointmentType; int? appointmentType;
AppointmentTypeEnum? appointmentTypeEnum;
ServiceAppointmentScheduleModel({ ServiceAppointmentScheduleModel({
this.serviceSlotList, this.serviceSlotList,
@ -30,6 +32,7 @@ class ServiceAppointmentScheduleModel {
this.amountTotal, this.amountTotal,
this.amountRem, this.amountRem,
this.appointmentType, this.appointmentType,
this.appointmentTypeEnum,
}); });
List<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() { List<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() {
@ -105,6 +108,7 @@ class ServiceAppointmentScheduleModel {
amountTotal = json['amountTotal']; amountTotal = json['amountTotal'];
amountRem = json['amountRem']; amountRem = json['amountRem'];
appointmentType = json['appointmentType']; appointmentType = json['appointmentType'];
appointmentTypeEnum = json['appointmentType'] != null ? (json['appointmentType'] as int).toAppointmentTypeEnum() : AppointmentTypeEnum.workshop;
} }
} }

@ -163,4 +163,9 @@ class MessageImageModel {
'reqOfferID': reqOfferID, // We don't include 'isFromNetwork' since it's set manually when parsing JSON 'reqOfferID': reqOfferID, // We don't include 'isFromNetwork' since it's set manually when parsing JSON
}; };
} }
@override
String toString() {
return 'MessageImageModel{id: $id, imageUrl: $imageUrl, imageStr: $imageStr, imagePath: $imagePath, isFromNetwork: $isFromNetwork, reqOfferID: $reqOfferID}';
}
} }

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:mc_common_app/utils/utils.dart';
class GenericRespModel { class GenericRespModel {
GenericRespModel({ GenericRespModel({
this.data, this.data,
@ -13,12 +15,19 @@ class GenericRespModel {
int? totalItemsCount; int? totalItemsCount;
String? message; String? message;
factory GenericRespModel.fromJson(Map<String, dynamic> json) => GenericRespModel( factory GenericRespModel.fromJson(Map<String, dynamic> json) {
if (json.containsKey('StatusMessage')) {
if ((json['StatusMessage'] as String).contains('Internal server error')) {
Utils.showToast("${json['StatusMessage']}");
}
}
return GenericRespModel(
data: json["data"], data: json["data"],
messageStatus: json["messageStatus"], messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"], totalItemsCount: json["totalItemsCount"],
message: json["message"], message: json["message"],
); );
}
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"data": data, "data": data,

@ -22,17 +22,17 @@ class Document {
String? message; String? message;
factory Document.fromJson(Map<String, dynamic> json) => Document( factory Document.fromJson(Map<String, dynamic> json) => Document(
totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], totalItemsCount: json["totalItemsCount"],
data: json["data"] == null ? null : List<DocumentData>.from(json["data"].map((x) => DocumentData.fromJson(x))), data: json["data"] == null ? null : List<DocumentData>.from(json["data"].map((x) => DocumentData.fromJson(x))),
messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], messageStatus: json["messageStatus"],
message: json["message"] == null ? null : json["message"], message: json["message"],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount == null ? null : totalItemsCount, "totalItemsCount": totalItemsCount,
"data": data == null ? null : List<dynamic>.from(data!.map((x) => x.toJson())), "data": data == null ? null : List<dynamic>.from(data!.map((x) => x.toJson())),
"messageStatus": messageStatus == null ? null : messageStatus, "messageStatus": messageStatus,
"message": message == null ? null : message, "message": message,
}; };
} }
@ -43,6 +43,7 @@ class DocumentData {
this.documentId, this.documentId,
this.documentUrl, this.documentUrl,
this.status, this.status,
this.statusText,
this.comment, this.comment,
this.isActive, this.isActive,
this.document, this.document,
@ -54,35 +55,37 @@ class DocumentData {
int? id; int? id;
int? serviceProviderId; int? serviceProviderId;
int? documentId; int? documentId;
dynamic? documentUrl; String? documentUrl;
int? status; int? status;
dynamic? comment; String? comment;
bool? isActive; bool? isActive;
String? document; String? document;
String? fileExt; String? fileExt;
String? statusText;
String? documentName; String? documentName;
bool? isLocalFile; bool? isLocalFile;
factory DocumentData.fromJson(Map<String, dynamic> json) => DocumentData( factory DocumentData.fromJson(Map<String, dynamic> json) => DocumentData(
id: json["id"] == null ? null : json["id"], id: json["id"],
serviceProviderId: json["serviceProviderID"] == null ? null : json["serviceProviderID"], serviceProviderId: json["serviceProviderID"],
documentId: json["documentID"] == null ? null : json["documentID"], documentId: json["documentID"],
documentUrl: json["documentURL"], documentUrl: json["documentURL"],
status: json["status"] == null ? null : json["status"], status: json["status"],
statusText: json["statusText"],
comment: json["comment"], comment: json["comment"],
isActive: json["isActive"] == null ? null : json["isActive"], isActive: json["isActive"],
document: null, document: null,
fileExt: null, fileExt: null,
documentName: json["documentName"] == null ? null : json["documentName"], documentName: json["documentName"],
isLocalFile: false); isLocalFile: false);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id == null ? null : id, "id": id,
"serviceProviderID": serviceProviderId == null ? null : serviceProviderId, "serviceProviderID": serviceProviderId,
"documentID": documentId == null ? null : documentId, "documentID": documentId,
"documentURL": documentUrl, "documentURL": documentUrl,
"status": status == null ? null : status, "status": status,
"comment": comment, "comment": comment,
"isActive": isActive == null ? null : isActive, "isActive": isActive,
}; };
} }

@ -1,7 +1,9 @@
import 'dart:developer'; import 'dart:developer';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.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/chat_models/chat_message_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class ProviderOffersModel { class ProviderOffersModel {
int? id; int? id;
@ -61,6 +63,7 @@ class ServiceProvidersOffers {
String? email; String? email;
String? companyName; String? companyName;
String? createdOn; String? createdOn;
RequestOfferStatusEnum? requestOfferStatusEnum;
int? offerCount; int? offerCount;
List<ChatMessageModel>? chatMessages; List<ChatMessageModel>? chatMessages;
@ -74,6 +77,7 @@ class ServiceProvidersOffers {
this.chatMessages, this.chatMessages,
this.providerUserId, this.providerUserId,
this.createdOn, this.createdOn,
this.requestOfferStatusEnum,
}); });
ServiceProvidersOffers.fromJson(Map<String, dynamic> json) { ServiceProvidersOffers.fromJson(Map<String, dynamic> json) {
@ -85,11 +89,12 @@ class ServiceProvidersOffers {
companyName = json['companyName']; companyName = json['companyName'];
offerCount = json['offerCount']; offerCount = json['offerCount'];
createdOn = json['createdOn']; createdOn = json['createdOn'];
requestOfferStatusEnum = ((json['offerStatusLast']) as int).toRequestOfferStatusEnum();
chatMessages = []; chatMessages = [];
} }
@override @override
String toString() { String toString() {
return 'ServiceProvidersOffers{providerUserId: $providerUserId, providerId: $providerId, name: $name, mobileNo: $mobileNo, email: $email, companyName: $companyName,offeredItemCreatedOn: $createdOn, offerCount: $offerCount, chatMessages: $chatMessages}'; return 'ServiceProvidersOffers{providerUserId: $providerUserId, providerId: $providerId, name: $name, mobileNo: $mobileNo, email: $email, companyName: $companyName,offeredItemCreatedOn: $createdOn, requestOfferStatusEnum: $requestOfferStatusEnum, offerCount: $offerCount, chatMessages: $chatMessages}';
} }
} }

@ -8,6 +8,8 @@ class RequestModel {
String requestTypeName; String requestTypeName;
String requestStatusName; String requestStatusName;
RequestStatusEnum requestStatus; RequestStatusEnum requestStatus;
int? shippingStatus;
ShippingRequestStatusEnum? shippingStatusEnum;
String cityName; String cityName;
String vehicleTypeName; String vehicleTypeName;
String countryName; String countryName;
@ -46,6 +48,8 @@ class RequestModel {
required this.requestTypeName, required this.requestTypeName,
required this.requestStatusName, required this.requestStatusName,
required this.requestStatus, required this.requestStatus,
required this.shippingStatus,
required this.shippingStatusEnum,
required this.cityName, required this.cityName,
required this.vehicleTypeName, required this.vehicleTypeName,
required this.countryName, required this.countryName,
@ -96,6 +100,8 @@ class RequestModel {
requestTypeName: json["requestTypeName"], requestTypeName: json["requestTypeName"],
requestStatusName: json["requestStatusName"], requestStatusName: json["requestStatusName"],
requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(), requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(),
shippingStatus: json['shippingRequestStatus'],
shippingStatusEnum: json['shippingRequestStatus'] != null ? (json['shippingRequestStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated,
cityName: json["cityName"], cityName: json["cityName"],
vehicleTypeName: json["vehicleTypeName"], vehicleTypeName: json["vehicleTypeName"],
countryName: json["countryName"], countryName: json["countryName"],

@ -42,7 +42,7 @@ class ItemData {
final String? price; final String? price;
final String? manufactureDate; final String? manufactureDate;
final String? description; final String? description;
final dynamic pictureUrl; final String? pictureUrl;
final int? companyId; final int? companyId;
final int? serviceProviderServiceId; final int? serviceProviderServiceId;
final String? serviceProviderServiceDescription; final String? serviceProviderServiceDescription;

@ -0,0 +1,26 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
class AppInfoModel {
int? id;
String? header;
String? content;
bool? isActive;
int? channel;
List<ImageModel>? appInfoImages;
AppInfoModel({this.id, this.header, this.content, this.isActive, this.channel, this.appInfoImages});
AppInfoModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
header = json['header'];
content = json['content'];
isActive = json['isActive'];
channel = json['channel'];
if (json['appInfoImages'] != null) {
appInfoImages = <ImageModel>[];
json['appInfoImages'].forEach((v) {
appInfoImages!.add(ImageModel.fromJson(v));
});
}
}
}

@ -0,0 +1,36 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
class ContactInfoModel {
int? id;
String? companyName;
String? mobileNo;
String? phoneNo;
String? email;
String? address;
String? latitude;
String? longitude;
int? channel;
bool? isActive;
List<ImageModel>? contactInfoImages;
ContactInfoModel({this.id, this.companyName, this.mobileNo, this.phoneNo, this.email, this.address, this.latitude, this.longitude, this.channel, this.isActive, this.contactInfoImages});
ContactInfoModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
companyName = json['companyName'];
mobileNo = json['mobileNo'];
phoneNo = json['phoneNo'];
email = json['email'];
address = json['address'];
latitude = json['latitude'];
longitude = json['longitude'];
channel = json['channel'];
isActive = json['isActive'];
if (json['contactInfoImages'] != null) {
contactInfoImages = <ImageModel>[];
json['contactInfoImages'].forEach((v) {
contactInfoImages!.add(ImageModel.fromJson(v));
});
}
}
}

@ -0,0 +1,32 @@
class FAQsModel {
int? id;
String? question;
String? answer;
int? sequenceNo;
bool? isActive;
int? channel;
bool? isCollapsed;
FAQsModel({this.id, this.question, this.answer, this.sequenceNo, this.isActive, this.channel, this.isCollapsed});
FAQsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
question = json['question'];
answer = json['answer'];
sequenceNo = json['sequenceNo'];
isActive = json['isActive'];
channel = json['channel'];
isCollapsed = false;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['question'] = question;
data['answer'] = answer;
data['sequenceNo'] = sequenceNo;
data['isActive'] = isActive;
data['channel'] = channel;
return data;
}
}

@ -0,0 +1,27 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class ShippingRequestModel {
int? id;
int? requestID;
RequestModel? request;
int? shippingStatus;
ShippingRequestStatusEnum? shippingStatusEnum;
String? deliveredOn;
String? comment;
String? createdOn;
ShippingRequestModel({this.id, this.requestID, this.request, this.shippingStatus, this.deliveredOn, this.comment, this.createdOn});
ShippingRequestModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
request = json['request'];
shippingStatus = json['shippingStatus'];
shippingStatusEnum = json['shippingStatus'] != null ? (json['shippingStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated;
deliveredOn = json['deliveredOn'];
comment = json['comment'];
createdOn = json['createdOn'];
}
}

@ -20,7 +20,7 @@ abstract class AdsRepo {
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}); Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew});
Future<List<AdDetailsModel>> getAllAds({required bool isMyAds}); Future<List<AdDetailsModel>> getAllAds({required bool isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum});
Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({List<String>? cityIdsList, List<String>? vehicleModelYearIdsList, List<String>? vehicleBrandIdsList, List<String>? createdByRolesIdsList}); Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({List<String>? cityIdsList, List<String>? vehicleModelYearIdsList, List<String>? vehicleBrandIdsList, List<String>? createdByRolesIdsList});
@ -30,7 +30,7 @@ abstract class AdsRepo {
Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId}); Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId});
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}); Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment});
Future<GenericRespModel> createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID}); Future<GenericRespModel> createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID});
@ -140,16 +140,26 @@ class AdsRepoImp implements AdsRepo {
} }
@override @override
Future<List<AdDetailsModel>> getAllAds({required isMyAds}) async { Future<List<AdDetailsModel>> getAllAds({required isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}) async {
var onlyMyAdsParams = { Map<String, dynamic> onlyMyAdsParams = {
"userID": appState.getUser.data!.userInfo!.userId ?? "", "userID": appState.getUser.data!.userInfo!.userId ?? "",
}; };
if (isMyAds && adPostStatus != null) {
onlyMyAdsParams.addAll({
"AdsStatuses": ["${adPostStatus.getIdFromAdPostStatusEnum()}"]
});
}
var allAdsParams = { var allAdsParams = {
"AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS "AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
"isActive": "true", //only Active ADS "isActive": "true", //only Active ADS
"isExplore": "true" "isExplore": "true"
}; };
if (!isMyAds && createdByRoleEnum != null) {
allAdsParams.addAll({
"CreatedByRoles": ["${createdByRoleEnum.getIdFromCreatedByRoleEnum()}"],
});
}
GenericRespModel adsGenericModel = await apiClient.getJsonForObject( GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken, token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
@ -263,11 +273,11 @@ class AdsRepoImp implements AdsRepo {
} }
@override @override
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async { Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment}) async {
var postParams = { var postParams = {
"id": adId, "id": adId,
"status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(), "status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(),
"comment": "", "comment": comment ?? "",
}; };
String token = appState.getUser.data!.accessToken ?? ""; String token = appState.getUser.data!.accessToken ?? "";

@ -4,11 +4,13 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/appointments_models/schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/schedule_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class AppointmentRepo { abstract class AppointmentRepo {
Future<List<AppointmentListModel>> getMyAppointmentsForProvider(Map<String, dynamic> map); Future<List<AppointmentListModel>> getMyAppointmentsForProvider(Map<String, dynamic> map);
@ -20,7 +22,7 @@ abstract class AppointmentRepo {
List<String>? branchIdsList, List<String>? branchIdsList,
}); });
Future<GenericRespModel> updateAppointmentStatus(Map<String, dynamic> map); Future<GenericRespModel> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum});
Future<GenericRespModel> updateAppointmentPaymentStatus(Map<String, dynamic> map); Future<GenericRespModel> updateAppointmentPaymentStatus(Map<String, dynamic> map);
@ -240,9 +242,13 @@ class AppointmentRepoImp implements AppointmentRepo {
} }
@override @override
Future<GenericRespModel> updateAppointmentStatus(Map<String, dynamic> map) async { Future<GenericRespModel> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum}) async {
String t = appState.getUser.data!.accessToken ?? ""; String t = appState.getUser.data!.accessToken ?? "";
return await apiClient.postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateAppointmentStatus, map, token: t); var params = {
"appointmentID": appointmentId.toString(),
"appointmentStatusID": appointmentStatusEnum.getIdFromAppointmentStatusEnum().toString(),
};
return await apiClient.postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateAppointmentStatus, params, token: t);
} }
@override @override

@ -196,7 +196,14 @@ class BranchRepoImp implements BranchRepo {
List<Map<String, dynamic>> map = []; List<Map<String, dynamic>> map = [];
for (int i = 0; i < documents!.length; i++) { for (int i = 0; i < documents!.length; i++) {
if (documents[i].document != null) { if (documents[i].document != null) {
var postParams = {"id": documents[i].id, "serviceProviderID": documents[i].serviceProviderId, "documentID": documents[i].documentId, "documentExt": documents[i].fileExt, "documentImage": documents[i].document, "isActive": true}; var postParams = {
"id": documents[i].id,
"serviceProviderID": documents[i].serviceProviderId,
"documentID": documents[i].documentId,
"documentExt": documents[i].fileExt,
"documentImage": documents[i].document,
"isActive": true,
};
map.add(postParams); map.add(postParams);
} }
} }

@ -33,6 +33,15 @@ abstract class ChatRepo {
int pageIndex = 0, int pageIndex = 0,
int pageSize = 0, int pageSize = 0,
}); });
Future<List<ChatMessageModel>> getUsersChatMessagesForGeneralChat({
String? userID,
int? adID,
int? adsChatBuyerId,
required bool isForBuyer,
int pageIndex = 0,
int pageSize = 0,
});
} }
class ChatRepoImp implements ChatRepo { class ChatRepoImp implements ChatRepo {
@ -66,6 +75,8 @@ class ChatRepoImp implements ChatRepo {
url = ApiConsts.messageIsReadUpdateForAds; url = ApiConsts.messageIsReadUpdateForAds;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) { } else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
url = ApiConsts.messageIsReadUpdateForRequests; url = ApiConsts.messageIsReadUpdateForRequests;
} else if (chatTypeEnum == ChatTypeEnum.general) {
url = ApiConsts.messageIsReadUpdateForRequests;
} }
var queryParameters = {"iDs": messageIds}; var queryParameters = {"iDs": messageIds};
GenericRespModel genericRespModel = await apiClient.postJsonForObject( GenericRespModel genericRespModel = await apiClient.postJsonForObject(
@ -144,4 +155,38 @@ class ChatRepoImp implements ChatRepo {
} }
return []; return [];
} }
@override
Future<List<ChatMessageModel>> getUsersChatMessagesForGeneralChat({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,
);
if (genericRespModel.messageStatus == 1 && genericRespModel.data != null) {
List<ChatMessageModel> chatMessages = List.generate(
genericRespModel.data.length,
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
);
return chatMessages;
}
return [];
}
} }

@ -11,6 +11,7 @@ import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/user_models/cities.dart'; import 'package:mc_common_app/models/user_models/cities.dart';
import 'package:mc_common_app/models/user_models/country.dart'; import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/role.dart'; import 'package:mc_common_app/models/user_models/role.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class CommonRepo { abstract class CommonRepo {
Future<Country> getAllCountries(); Future<Country> getAllCountries();
@ -129,6 +130,22 @@ class CommonRepoImp implements CommonRepo {
{"id": 2, "enumTypeID": 0, "enumValueStr": "Used", "enumValue": 2, "isActive": true}, {"id": 2, "enumTypeID": 0, "enumValueStr": "Used", "enumValue": 2, "isActive": true},
], ],
}; };
List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
return enums;
}
if (enumTypeID == -2) {
// This is for the ShippingRequestStatus which will be added to API later
final Map<String, dynamic> json = {
"data": [
{"id": 1, "enumTypeID": 0, "enumValueStr": "Initiated", "enumValue": 1, "isActive": true},
{"id": 2, "enumTypeID": 0, "enumValueStr": "In Transit", "enumValue": 2, "isActive": true},
{"id": 3, "enumTypeID": 0, "enumValueStr": "Out for Delivery", "enumValue": 3, "isActive": true},
{"id": 4, "enumTypeID": 0, "enumValueStr": "Delivered", "enumValue": 4, "isActive": true},
],
};
List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index])); List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
return enums; return enums;
} }

@ -20,7 +20,6 @@ class ItemsRepoImp implements ItemsRepo {
@override @override
Future<GenericRespModel> createServiceItems(Map map) async { Future<GenericRespModel> createServiceItems(Map map) async {
String t = AppState().getUser.data!.accessToken ?? ""; String t = AppState().getUser.data!.accessToken ?? "";
debugPrint(t);
return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.createItems, map, token: t); return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.createItems, map, token: t);
} }
@ -30,7 +29,6 @@ class ItemsRepoImp implements ItemsRepo {
"ServiceProviderServiceID": serviceId.toString(), "ServiceProviderServiceID": serviceId.toString(),
}; };
String? token = AppState().getUser.data?.accessToken; String? token = AppState().getUser.data?.accessToken;
debugPrint(token);
return await injector return await injector
.get<ApiClient>() .get<ApiClient>()
.getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? ""); .getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? "");
@ -39,7 +37,6 @@ class ItemsRepoImp implements ItemsRepo {
@override @override
Future<GenericRespModel> updateServiceItem(Map map) async { Future<GenericRespModel> updateServiceItem(Map map) async {
String t = AppState().getUser.data!.accessToken ?? ""; String t = AppState().getUser.data!.accessToken ?? "";
debugPrint(t);
return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateServiceItem, map, token: t); return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateServiceItem, map, token: t);
} }

@ -2,11 +2,15 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart'; import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class PaymentsRepo { abstract class PaymentsRepo {
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentId, required int adId}); Future<bool> verifyPayment({required int paymentTypeId, required int id, bool isForAppointments = false, List<int>? appointmentIds});
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentTypeId, required int adId});
} }
class PaymentsRepoImp implements PaymentsRepo { class PaymentsRepoImp implements PaymentsRepo {
@ -14,9 +18,67 @@ class PaymentsRepoImp implements PaymentsRepo {
AppState appState = injector.get<AppState>(); AppState appState = injector.get<AppState>();
@override @override
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentId, required int adId}) async { Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentTypeId, required int adId}) async {
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.payForOrderDetailGet); var queryParameters = {
"AdsID": adId.toString(),
"PaymentType": paymentTypeId.toString(),
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
queryParameters: queryParameters,
(json) => GenericRespModel.fromJson(json),
ApiConsts.payForOrderDetailGet,
);
PayOrderDetailRespModel payOrderDetailRespModel = PayOrderDetailRespModel.fromJson(adsGenericModel.data); PayOrderDetailRespModel payOrderDetailRespModel = PayOrderDetailRespModel.fromJson(adsGenericModel.data);
return payOrderDetailRespModel; return payOrderDetailRespModel;
} }
String getKeyByPaymentType({required int paymentType}) {
PaymentTypes paymentTypeEnum = paymentType.getPaymentTypeFromId();
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
return "SubscriptionAppliedID";
case PaymentTypes.appointment:
case PaymentTypes.partialAppointment:
return "appointmentIds";
case PaymentTypes.ads:
case PaymentTypes.adReserve:
case PaymentTypes.extendAds:
return "AdsID";
case PaymentTypes.request:
return "RequestID";
}
}
@override
Future<bool> verifyPayment({required int paymentTypeId, required int id, bool isForAppointments = false, List<int>? appointmentIds}) async {
Map<String, dynamic> queryParameters = {
"ID": id.toString(),
"PaymentType": paymentTypeId.toString(),
};
if (isForAppointments) {
List<String> ids = [];
if (appointmentIds != null) {
for (var element in appointmentIds) {
ids.add(element.toString());
}
}
queryParameters.removeWhere((key, value) => key == "ID");
queryParameters.addAll({"IDs": ids});
}
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
queryParameters: queryParameters,
(json) => GenericRespModel.fromJson(json),
ApiConsts.payForOrderIsPaidGet,
);
if (adsGenericModel.data == null) {
return false;
}
bool isPaid = adsGenericModel.data['isPaid'] ?? false;
return isPaid;
}
} }

@ -0,0 +1,84 @@
import 'package:easy_localization/easy_localization.dart';
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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class SettingOptionsRepo {
Future<List<FAQsModel>> getAllFaqs();
Future<List<ContactInfoModel>> getAllContactInfos();
Future<List<AppInfoModel>> getAppInfoList();
}
class SettingOptionsRepoImp extends SettingOptionsRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<List<FAQsModel>> getAllFaqs() async {
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getAllFAQs,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<FAQsModel> list = List.generate(genericRespModel.data.length, (index) => FAQsModel.fromJson(genericRespModel.data[index]));
return list;
}
@override
Future<List<ContactInfoModel>> getAllContactInfos() async {
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getContactInfo,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<ContactInfoModel> list = List.generate(genericRespModel.data.length, (index) => ContactInfoModel.fromJson(genericRespModel.data[index]));
return list;
}
@override
Future<List<AppInfoModel>> getAppInfoList() async {
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getAppInfo,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<AppInfoModel> list = List.generate(genericRespModel.data.length, (index) => AppInfoModel.fromJson(genericRespModel.data[index]));
return list;
}
}

@ -0,0 +1,72 @@
import 'package:easy_localization/easy_localization.dart';
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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class ShippingRepo {
Future<List<ShippingRequestModel>> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId});
Future<GenericRespModel> updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment});
}
class ShippingRepoImp extends ShippingRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<List<ShippingRequestModel>> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId}) async {
String token = appState.getUser.data!.accessToken ?? "";
Map<String, String> queryParameters = {
"requestID": "${requestId ?? 0}",
"shippingStatus": "${shippingStatusEnum != null ? shippingStatusEnum.getIdFromShippingStatusEnum() : 0}",
};
GenericRespModel genericRespModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.shippingRequestStatusGet,
queryParameters,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<ShippingRequestModel> list = List.generate(genericRespModel.data.length, (index) => ShippingRequestModel.fromJson(genericRespModel.data[index]));
return list;
}
@override
Future<GenericRespModel> updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment}) async {
String token = appState.getUser.data!.accessToken ?? "";
Map<String, String> queryParameters = {
"id": "$shippingRequestId",
"shippingStatus": "${shippingStatusEnum.getIdFromShippingStatusEnum()}",
"comment": comment ?? "",
};
GenericRespModel genericRespModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.shippingRequestStatusUpdate,
queryParameters,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
}
return genericRespModel;
}
}

@ -79,7 +79,7 @@ class CommonServicesImp implements CommonAppServices {
final status = await AppPermissions.checkStoragePermissions(context); final status = await AppPermissions.checkStoragePermissions(context);
if (status) { if (status) {
result = await FilePicker.platform.pickFiles(allowMultiple: true, type: fileType, allowedExtensions: allowedExtensions); result = await FilePicker.platform.pickFiles(allowMultiple: false, type: fileType, allowedExtensions: allowedExtensions);
} }
List<File> pickedFiles = []; List<File> pickedFiles = [];
@ -109,6 +109,4 @@ class CommonServicesImp implements CommonAppServices {
return 0.0; return 0.0;
} }
} }
} }

@ -26,36 +26,16 @@ abstract class PaymentService {
class PaymentServiceImp implements PaymentService { class PaymentServiceImp implements PaymentService {
MyInAppBrowser? myInAppBrowser; MyInAppBrowser? myInAppBrowser;
var inAppBrowserOptions = InAppBrowserClassOptions(
inAppWebViewGroupOptions: InAppWebViewGroupOptions(crossPlatform: InAppWebViewOptions(useShouldOverrideUrlLoading: true, transparentBackground: false), ios: IOSInAppWebViewOptions(applePayAPIEnabled: true)),
crossPlatform: InAppBrowserOptions(hideUrlBar: true, toolbarTopBackgroundColor: Colors.black),
android: AndroidInAppBrowserOptions(),
ios: IOSInAppBrowserOptions(hideToolbarBottom: true, toolbarBottomBackgroundColor: Colors.white, closeButtonColor: Colors.white, presentationStyle: IOSUIModalPresentationStyle.OVER_FULL_SCREEN));
var inAppBrowserOptions = InAppBrowserClassSettings( String getUrlRequestByPaymentId({required int id, List<int>? appointmentIds, required PaymentTypes paymentType}) {
webViewSettings: InAppWebViewSettings(
useShouldOverrideUrlLoading: false,
transparentBackground: false,
isInspectable: false,
applePayAPIEnabled: true,
cacheEnabled: false,
),
browserSettings: InAppBrowserSettings(
hideUrlBar: true,
hideTitleBar: true,
hideDefaultMenuItems: false,
toolbarBottomBackgroundColor: Colors.black,
closeButtonColor: Colors.white,
presentationStyle: ModalPresentationStyle.OVER_FULL_SCREEN,
// toolbarTopBackgroundColor: Colors.black
),
);
@override
Future<void> placePayment({
required int id,
List<int>? appointmentIds,
required PaymentTypes paymentType,
required Function() onSuccess,
required Function() onFailure,
}) async {
String urlRequest = ""; String urlRequest = "";
int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0; int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;
switch (paymentType) { switch (paymentType) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&OrderProviderSubscriptionID=$id"; urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&OrderProviderSubscriptionID=$id";
@ -86,24 +66,29 @@ class PaymentServiceImp implements PaymentService {
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&RequestID=$id"; urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&RequestID=$id";
break; break;
} }
return urlRequest;
}
@override
Future<void> placePayment({
required int id,
List<int>? appointmentIds,
required PaymentTypes paymentType,
required Function() onSuccess,
required Function() onFailure,
}) async {
String urlRequest = getUrlRequestByPaymentId(id: id, paymentType: paymentType, appointmentIds: appointmentIds);
log("PaymentUrl: $urlRequest"); log("PaymentUrl: $urlRequest");
myInAppBrowser = MyInAppBrowser( myInAppBrowser = MyInAppBrowser(onExitCallback: () {
onExitCallback: () {
log("Browser Exited"); log("Browser Exited");
}, }, onLoadStartCallback: (String url) {
onLoadStartCallback: (String url) {
log("Browser LoadStart for : $url"); log("Browser LoadStart for : $url");
onBrowserLoadStart(onFailure: onFailure, onSuccess: onSuccess, url: url); onBrowserLoadStart(onFailure: onFailure, onSuccess: onSuccess, url: url);
}, });
);
await myInAppBrowser!.openUrlRequest( await myInAppBrowser!.openUrlRequest(
urlRequest: URLRequest( urlRequest: URLRequest(url: Uri.parse(urlRequest)),
url: WebUri('${Uri.parse(urlRequest)}', forceToStringRawValue: true), options: inAppBrowserOptions,
allowsCellularAccess: true,
allowsConstrainedNetworkAccess: true,
allowsExpensiveNetworkAccess: true,
),
settings: inAppBrowserOptions,
); );
} }

@ -16,6 +16,7 @@ class AppEnums {
static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums
static const int requestStatusesFilterEnumId = 15; // Appointments Filter Enums static const int requestStatusesFilterEnumId = 15; // Appointments Filter Enums
static const int conditionEnumId = -1; // to get the Condition Filter Enums static const int conditionEnumId = -1; // to get the Condition Filter Enums
static const int shippingStatusEnumId = -2; // to get the Shipping Filter Enums
} }
enum VehicleType { enum VehicleType {
@ -78,7 +79,15 @@ enum PaymentMethods {
tamara, tamara,
} }
enum PaymentTypes { subscription, appointment, adReserve, ads, request, extendAds, partialAppointment } enum PaymentTypes {
subscription,
appointment,
adReserve,
ads,
request,
extendAds,
partialAppointment,
}
enum AdCreationSteps { enum AdCreationSteps {
vehicleDetails, vehicleDetails,
@ -138,6 +147,11 @@ enum BranchStatusEnum {
deactivated // 6 deactivated // 6
} }
enum AppointmentTypeEnum {
workshop,
home,
}
enum AppointmentStatusEnum { enum AppointmentStatusEnum {
booked, booked,
confirmed, confirmed,
@ -197,3 +211,11 @@ enum SubscriptionActionTypeEnum {
users, users,
branches, branches,
} }
enum ShippingRequestStatusEnum {
allRequests,
initiated,
inTransit,
outForDelivery,
delivered,
}

@ -8,6 +8,7 @@ import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
@ -196,7 +197,7 @@ class Utils {
return MyColors.adPendingStatusColor; return MyColors.adPendingStatusColor;
case AdPostStatus.pendingForPayment: case AdPostStatus.pendingForPayment:
return MyColors.adPendingStatusColor; return MyColors.submittedColor;
case AdPostStatus.rejected: case AdPostStatus.rejected:
return MyColors.adCancelledStatusColor; return MyColors.adCancelledStatusColor;
@ -205,10 +206,10 @@ class Utils {
return MyColors.adCancelledStatusColor; return MyColors.adCancelledStatusColor;
case AdPostStatus.pendingForPost: case AdPostStatus.pendingForPost:
return MyColors.adPendingStatusColor; return MyColors.inProgressColor;
case AdPostStatus.active: case AdPostStatus.active:
return MyColors.adActiveStatusColor; return MyColors.greenColor;
case AdPostStatus.expired: case AdPostStatus.expired:
return MyColors.adCancelledStatusColor; return MyColors.adCancelledStatusColor;
@ -249,6 +250,80 @@ class Utils {
} }
} }
static Color getChipColorByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) {
switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer:
return MyColors.pendingColor;
case RequestOfferStatusEnum.negotiate:
return MyColors.submittedColor;
case RequestOfferStatusEnum.accepted:
return MyColors.completedColor;
case RequestOfferStatusEnum.rejected:
return MyColors.cancelledColor;
case RequestOfferStatusEnum.cancel:
return MyColors.redColor;
}
}
static String getNameByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) {
switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer:
return "Pending";
case RequestOfferStatusEnum.negotiate:
return "Negotiate";
case RequestOfferStatusEnum.accepted:
return "Accepted";
case RequestOfferStatusEnum.rejected:
return "Rejected";
case RequestOfferStatusEnum.cancel:
return "Cancelled";
}
}
static String getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
switch (shippingRequestStatusEnum) {
case ShippingRequestStatusEnum.allRequests:
return "All Requests";
case ShippingRequestStatusEnum.initiated:
return "Initiated";
case ShippingRequestStatusEnum.inTransit:
return "In Transit";
case ShippingRequestStatusEnum.outForDelivery:
return "Out For Delivery";
case ShippingRequestStatusEnum.delivered:
return "Delivered";
}
}
static Color getChipColorByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
switch (shippingRequestStatusEnum) {
case ShippingRequestStatusEnum.allRequests:
return MyColors.submittedColor;
case ShippingRequestStatusEnum.initiated:
return MyColors.submittedColor;
case ShippingRequestStatusEnum.inTransit:
return MyColors.shippingColor;
case ShippingRequestStatusEnum.outForDelivery:
return MyColors.deliveryColor;
case ShippingRequestStatusEnum.delivered:
return MyColors.greenColor;
}
}
static Color getChipColorByBranchStatus(BranchStatusEnum branchStatusEnum) { static Color getChipColorByBranchStatus(BranchStatusEnum branchStatusEnum) {
switch (branchStatusEnum) { switch (branchStatusEnum) {
case BranchStatusEnum.pending: case BranchStatusEnum.pending:
@ -498,4 +573,16 @@ class Utils {
actionButtonNo: const SizedBox(), actionButtonNo: const SizedBox(),
); );
} }
static Widget buildStatusContainer(String text) {
return Center(
child: text.toText(color: MyColors.lightTextColor, fontSize: 14),
).toContainer(
marginAll: 8,
paddingAll: 15,
borderRadius: 8,
width: double.infinity,
backgroundColor: MyColors.grey98Color.withOpacity(0.1),
);
}
} }

@ -198,7 +198,7 @@ class AdVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
applyFilterOnExploreAds({required CreatedByRoleEnum createdByRoleFilter}) { applyFilterOnExploreAds({required CreatedByRoleEnum createdByRoleFilter}) async {
if (exploreAdsFilterOptions.isEmpty) return; if (exploreAdsFilterOptions.isEmpty) return;
int index = exploreAdsFilterOptions.indexWhere((element) => element.id.toCreatedByRoleEnum() == createdByRoleFilter); int index = exploreAdsFilterOptions.indexWhere((element) => element.id.toCreatedByRoleEnum() == createdByRoleFilter);
@ -211,13 +211,18 @@ class AdVM extends BaseVM {
notifyListeners(); notifyListeners();
return; return;
} }
setState(ViewState.busy);
exploreAdsFilteredList = exploreAds.where((element) => element.createdByRoleEnum == createdByRoleFilter).toList(); exploreAdsFilteredList = await getAdsByFilter(createdByRoleEnum: createdByRoleFilter, isMyAds: false);
setState(ViewState.idle);
notifyListeners(); notifyListeners();
} }
applyFilterOnMyAds({required AdPostStatus adPostStatusEnum}) { Future<List<AdDetailsModel>> getAdsByFilter({AdPostStatus? adPostStatus, required bool isMyAds, CreatedByRoleEnum? createdByRoleEnum}) async {
return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum);
}
applyFilterOnMyAds({required AdPostStatus adPostStatusEnum}) async {
if (myAdsFilterOptions.isEmpty) return; if (myAdsFilterOptions.isEmpty) return;
int index = myAdsFilterOptions.indexWhere((element) => element.id.toAdPostEnum() == adPostStatusEnum); int index = myAdsFilterOptions.indexWhere((element) => element.id.toAdPostEnum() == adPostStatusEnum);
@ -240,8 +245,9 @@ class AdVM extends BaseVM {
notifyListeners(); notifyListeners();
return; return;
} }
setState(ViewState.busy);
myAdsFilteredList = myAds.where((element) => element.statusID! == adPostStatusEnum.getIdFromAdPostStatusEnum()).toList(); myAdsFilteredList = await getAdsByFilter(adPostStatus: adPostStatusEnum, isMyAds: true);
setState(ViewState.idle);
notifyListeners(); notifyListeners();
} }
@ -323,7 +329,7 @@ class AdVM extends BaseVM {
return; return;
} }
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.showToast(respModel.message ?? "A has been marked as sold successfully!"); Utils.showToast(respModel.message ?? "Ad has been marked as sold successfully!");
updateIsExploreAds(false); updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.sold); //pending for review applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.sold); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard); navigateReplaceWithName(context, AppRoutes.dashboard);
@ -361,9 +367,9 @@ class AdVM extends BaseVM {
navigateReplaceWithName(context, AppRoutes.dashboard); navigateReplaceWithName(context, AppRoutes.dashboard);
} }
Future<void> deactivateTheAd(BuildContext context, {required int adId}) async { Future<void> deactivateTheAd(BuildContext context, {required int adId, String? comment}) async {
Utils.showLoading(context); Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled); GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled, comment: comment);
if (respModel.messageStatus != 1) { if (respModel.messageStatus != 1) {
Utils.hideLoading(context); Utils.hideLoading(context);
@ -372,8 +378,9 @@ class AdVM extends BaseVM {
} }
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.showToast(LocaleKeys.adDeactivatedSuccessfully.tr()); Utils.showToast(LocaleKeys.adDeactivatedSuccessfully.tr());
updateDeactivateAdReasonDescription('');
updateIsExploreAds(false); updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //pending for review applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //Cacncelled
navigateReplaceWithName(context, AppRoutes.dashboard); navigateReplaceWithName(context, AppRoutes.dashboard);
} }
@ -580,6 +587,76 @@ class AdVM extends BaseVM {
reservationCancelReason = value; reservationCancelReason = value;
} }
List<OfferRequestCommentModel> deActivateAdModelList = [
OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
),
OfferRequestCommentModel(
index: 1,
isSelected: false,
title: LocaleKeys.veryHighPrice.tr(),
),
OfferRequestCommentModel(
index: 2,
isSelected: false,
title: LocaleKeys.alreadySold.tr(),
),
OfferRequestCommentModel(
index: 3,
isSelected: false,
title: LocaleKeys.customerNotResponding.tr(),
),
OfferRequestCommentModel(
index: 4,
isSelected: false,
title: LocaleKeys.otherVar.tr(),
),
];
OfferRequestCommentModel selectedDeActivateAdCommentModel = OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
);
void updateSelectionInDeActivateAdModelList(int index) {
for (var value in deActivateAdModelList) {
value.isSelected = false;
}
selectedDeActivateAdCommentModel = deActivateAdModelList[index];
deActivateAdModelList[index].isSelected = true;
notifyListeners();
}
String deactivateAdReasonDescription = "";
String deactivateAdReasonDescriptionError = "";
void updateDeactivateAdReasonDescription(String value) {
deactivateAdReasonDescription = value;
if (value.isNotEmpty) {
deactivateAdReasonDescriptionError = "";
}
}
bool isDeActivateReasonSubmitValidated() {
if (selectedDeActivateAdCommentModel.index != deActivateAdModelList.length - 1) {
return true;
}
bool isValidated = true;
if (deactivateAdReasonDescription.isEmpty) {
deactivateAdReasonDescriptionError = GlobalConsts.descriptionError;
isValidated = false;
} else {
deactivateAdReasonDescriptionError = "";
}
notifyListeners();
return isValidated;
}
String completeDealNotesForAdmin = ""; String completeDealNotesForAdmin = "";
void updateCompleteDealNotesForAdmin(String value) { void updateCompleteDealNotesForAdmin(String value) {
@ -1909,6 +1986,12 @@ class ImageModel {
ImageModel({this.id, this.filePath, this.isFromNetwork}); ImageModel({this.id, this.filePath, this.isFromNetwork});
ImageModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
filePath = json['image'];
isFromNetwork = true;
}
@override @override
String toString() { String toString() {
return 'ImageModel{id: $id, isFromNetwork: $isFromNetwork, filePath: $filePath}'; return 'ImageModel{id: $id, isFromNetwork: $isFromNetwork, filePath: $filePath}';

@ -2,6 +2,7 @@ import 'dart:developer';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; 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/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
@ -225,6 +226,8 @@ class AppointmentsVM extends BaseVM {
branchSelectedServiceId = id; branchSelectedServiceId = id;
currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId); currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
log("currentServiceSelection isAllowAppointmentHome: ${currentServiceSelection!.isAllowAppointmentHome}");
log("currentServiceSelection serviceDescription: ${currentServiceSelection!.serviceDescription}");
notifyListeners(); notifyListeners();
} }
@ -382,10 +385,10 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.idle); setState(ViewState.idle);
} }
updateAppointmentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async { updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy); if (isNeedToRebuild) setState(ViewState.busy);
try { try {
GenericRespModel genericRespModel = await appointmentRepo.updateAppointmentStatus(map); GenericRespModel genericRespModel = await appointmentRepo.updateAppointmentStatus(appointmentId: appointmentId, appointmentStatusEnum: appointmentStatusEnum);
if (genericRespModel.messageStatus == 1) { if (genericRespModel.messageStatus == 1) {
Utils.showToast(LocaleKeys.appointmentStatusUpdated.tr()); Utils.showToast(LocaleKeys.appointmentStatusUpdated.tr());
@ -1496,4 +1499,44 @@ class AppointmentsVM extends BaseVM {
} }
setState(ViewState.idle); setState(ViewState.idle);
} }
// Chat Related
Future<void> getGeneralChatsListForProvider({required BuildContext context}) async {
try {
// Utils.showLoading(context);
// List<BuyersChatForAdzsModel> buyersChatList = await appointmentRepo.getChatBuyersForAds(adsID: adsID);
// Utils.hideLoading(context);
// buyersChatListForAds.clear();
// buyersChatListForAds = buyersChatList;
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
}
void onGeneralChatMessagesButtonPressed({required BuildContext context}) async {
final myUserID = AppState().getUser.data!.userInfo!.userId;
// if (adDetailsModel.isMyAd != null && adDetailsModel.isMyAd!) {
// await getGeneralChatsListForProvider(context: context);
// // navigateWithName(context, AppRoutes.generalChatsListForProvider, 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,
// senderName: adDetailsModel.adOwnerName,
// )
// .whenComplete(() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments));
// }
}
} }

@ -1,7 +1,8 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
class BaseVM extends ChangeNotifier { class BaseVM extends ChangeNotifier {
ViewState _state = ViewState.idle; ViewState _state = ViewState.idle;
bool isInternetConnection = true; bool isInternetConnection = true;

@ -193,14 +193,6 @@ class ChatVM extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async {
for (var msg in messages) {
currentMessagesForAds.add(msg);
}
scrollChatDown();
notifyListeners();
}
void subscribeToReceiveRequestOfferMessages(BuildContext context) { void subscribeToReceiveRequestOfferMessages(BuildContext context) {
hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List<Object?>? arguments) { hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return; if (arguments == null || arguments.isEmpty) return;
@ -215,18 +207,19 @@ class ChatVM extends ChangeNotifier {
}); });
} }
void subscribeToReceiveAdMessages(BuildContext context) { Future<bool> markMessagesAsRead(BuildContext context, List<int> messageIds, ChatTypeEnum chatTypeEnum) async {
hubConnection!.on(SignalrConsts.receiveMessageAds, (List<Object?>? arguments) { bool status = false;
if (arguments == null || arguments.isEmpty) return; try {
List<ChatMessageModel> chat = []; // Utils.showLoading(context);
for (var message in arguments) { status = await chatRepo.markMessageAsRead(messageIds: messageIds, chatTypeEnum: chatTypeEnum);
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>); // Utils.hideLoading(context);
chat.add(chatMessage); } catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
// Utils.hideLoading(context);
status = false;
} }
onNewMessageReceivedForAds(messages: chat); return status;
logger.i(arguments);
// Utils.showToast(arguments.toString());
});
} }
Future<void> buildHubConnection(BuildContext context) async { Future<void> buildHubConnection(BuildContext context) async {
@ -236,6 +229,7 @@ class ChatVM extends ChangeNotifier {
await hubConnection!.start(); await hubConnection!.start();
subscribeToReceiveRequestOfferMessages(context); subscribeToReceiveRequestOfferMessages(context);
subscribeToReceiveAdMessages(context); subscribeToReceiveAdMessages(context);
subscribeToReceiveGeneralMessages(context);
hubConnection!.onclose((exception) { hubConnection!.onclose((exception) {
logger.i("onClose: ${exception.toString()}"); logger.i("onClose: ${exception.toString()}");
buildHubConnection(context); buildHubConnection(context);
@ -303,11 +297,7 @@ class ChatVM extends ChangeNotifier {
MessageImageModel convertFileToMessageImageModel({required File file}) { MessageImageModel convertFileToMessageImageModel({required File file}) {
List<int> imageBytes = file.readAsBytesSync(); List<int> imageBytes = file.readAsBytesSync();
String image = base64Encode(imageBytes); String image = base64Encode(imageBytes);
MessageImageModel vehiclePostingImages = MessageImageModel(imageStr: image, MessageImageModel vehiclePostingImages = MessageImageModel(imageStr: image, id: 0, isFromNetwork: false, reqOfferID: latestOfferId, imagePath: file.path);
id: 0,
isFromNetwork: false,
reqOfferID: latestOfferId,
imagePath: file.path);
return vehiclePostingImages; return vehiclePostingImages;
} }
@ -376,7 +366,7 @@ class ChatVM extends ChangeNotifier {
"ReceiverUserID": receiverId, "ReceiverUserID": receiverId,
"SenderUserID": userId, "SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message, "ChatText": chatMessageType == ChatMessageTypeEnum.image ? "${messageImages.length} Image(s)" : message,
"RequestID": requestId, "RequestID": requestId,
"ReqOfferID": latestOfferId, "ReqOfferID": latestOfferId,
}; };
@ -413,10 +403,7 @@ class ChatVM extends ChangeNotifier {
serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel); serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel);
} }
} else { } else {
int providerIndex = context int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
.read<RequestsVM>()
.myFilteredRequests
.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
log("providerIndex2:$providerIndex"); log("providerIndex2:$providerIndex");
if (providerIndex != -1) { if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex); context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
@ -444,7 +431,7 @@ class ChatVM extends ChangeNotifier {
} }
} }
Future<void> getUsersChatMessagesForCustomer({ Future<void> getRequestsChatMessagesForCustomer({
required BuildContext context, required BuildContext context,
required int providerId, required int providerId,
required int requestOfferId, required int requestOfferId,
@ -468,6 +455,17 @@ class ChatVM extends ChangeNotifier {
} }
} }
} }
List<int> unreadMessageIds = [];
for (var msg in chatMessages) {
if (!msg.isRead! && !msg.isMyMessage!) {
unreadMessageIds.add(msg.id!);
}
}
if (unreadMessageIds.isNotEmpty) {
await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.requestOffer);
}
Utils.hideLoading(context); Utils.hideLoading(context);
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
@ -477,7 +475,7 @@ class ChatVM extends ChangeNotifier {
} }
} }
Future<void> getUsersChatMessagesForProvider({ Future<void> getRequestsChatMessagesForProvider({
required BuildContext context, required BuildContext context,
required int customerId, required int customerId,
required int requestOfferId, required int requestOfferId,
@ -489,6 +487,15 @@ class ChatVM extends ChangeNotifier {
Utils.showLoading(context); Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessagesForRequests(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); context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context);
List<int> unreadMessageIds = [];
for (var msg in chatMessages) {
if (!msg.isRead! && !msg.isMyMessage!) {
unreadMessageIds.add(msg.id!);
}
}
if (unreadMessageIds.isNotEmpty) {
await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.requestOffer);
}
Utils.hideLoading(context); Utils.hideLoading(context);
} catch (e) { } catch (e) {
logger.i(e.toString()); logger.i(e.toString());
@ -578,7 +585,7 @@ class ChatVM extends ChangeNotifier {
for (var msg in currentMessagesForAds) { for (var msg in currentMessagesForAds) {
msg.senderName = senderName ?? ""; msg.senderName = senderName ?? "";
if (!msg.isRead!) { if (!msg.isRead! && !msg.isMyMessage!) {
unreadMessageIds.add(msg.id!); unreadMessageIds.add(msg.id!);
} }
} }
@ -595,22 +602,137 @@ class ChatVM extends ChangeNotifier {
} }
} }
Future<bool> markMessagesAsRead(BuildContext context, List<int> messageIds, ChatTypeEnum chatTypeEnum) async { void subscribeToReceiveAdMessages(BuildContext context) {
bool status = false; 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> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async {
for (var msg in messages) {
currentMessagesForAds.add(msg);
}
scrollChatDown();
notifyListeners();
}
Future<bool> onTextMessageSendForAds({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
required int adId,
required BuildContext context,
}) async {
if (message.isEmpty) return false;
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
logger.i("Hub Not Connected!!");
await buildHubConnection(context);
}
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>[obj],
).catchError((e) {
logger.i("error in invoking SendMessage: ${e.toString()}");
Utils.showToast(e.toString());
return false;
});
ChatMessageModel chatMessageModel = ChatMessageModel(
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
chatText: message,
isMyMessage: true,
senderName: name,
senderUserID: userId,
chatMessageTypeEnum: ChatMessageTypeEnum.freeText,
receiverUserID: receiverId,
);
currentMessagesForAds.add(chatMessageModel);
notifyListeners();
if (AppState().currentAppType == AppType.customer) {
} else {}
return true;
}
return false;
}
// ========================General ==================
List<ChatMessageModel> currentMessagesForGeneralChat = [];
Future<void> getUsersChatMessagesForGeneralChat({required BuildContext context, int? adID, int? adsChatBuyerId, String? userID, String? senderName, required bool isForBuyer}) async {
try { try {
Utils.showLoading(context); Utils.showLoading(context);
status = await chatRepo.markMessageAsRead(messageIds: messageIds, chatTypeEnum: chatTypeEnum); currentMessagesForGeneralChat = await chatRepo.getUsersChatMessagesForGeneralChat(userID: userID, adID: adID, isForBuyer: isForBuyer, adsChatBuyerId: adsChatBuyerId);
Utils.hideLoading(context); Utils.hideLoading(context);
List<int> unreadMessageIds = [];
for (var msg in currentMessagesForGeneralChat) {
msg.senderName = senderName ?? "";
if (!msg.isRead! && !msg.isMyMessage!) {
unreadMessageIds.add(msg.id!);
}
}
if (unreadMessageIds.isNotEmpty) {
await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.general);
}
notifyListeners();
} catch (e) { } catch (e) {
logger.i(e.toString()); logger.i(e.toString());
Utils.showToast(e.toString()); Utils.showToast(e.toString());
Utils.hideLoading(context); Utils.hideLoading(context);
status = false;
} }
return status;
} }
Future<bool> onTextMessageSendForAds({ Future<void> onNewMessageReceivedForGeneral({required List<ChatMessageModel> messages}) async {
for (var msg in messages) {
currentMessagesForAds.add(msg);
}
scrollChatDown();
notifyListeners();
}
void subscribeToReceiveGeneralMessages(BuildContext context) {
hubConnection!.on(SignalrConsts.receiveMessageGeneral, (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);
}
onNewMessageReceivedForGeneral(messages: chat);
logger.i(arguments);
// Utils.showToast(arguments.toString());
});
}
Future<bool> onTextMessageSendForGeneralChat({
required String receiverId, required String receiverId,
required ChatMessageTypeEnum chatMessageType, required ChatMessageTypeEnum chatMessageType,
required String message, required String message,
@ -629,15 +751,13 @@ class ChatVM extends ChangeNotifier {
final name = AppState().getUser.data!.userInfo!.firstName.toString(); final name = AppState().getUser.data!.userInfo!.firstName.toString();
final obj = <String, dynamic>{ final obj = <String, dynamic>{
"ReceiverUserID": receiverId, "ReceiverUserID": receiverId,
// "SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message, "ChatText": message,
"AdsID": adId,
}; };
logger.i("$obj"); logger.i("$obj");
hubConnection!.invoke( hubConnection!.invoke(
SignalrConsts.sendMessageAds, SignalrConsts.sendMessageGeneral,
args: <Object>[obj], args: <Object>[obj],
).catchError((e) { ).catchError((e) {
logger.i("error in invoking SendMessage: ${e.toString()}"); logger.i("error in invoking SendMessage: ${e.toString()}");
@ -655,11 +775,11 @@ class ChatVM extends ChangeNotifier {
receiverUserID: receiverId, receiverUserID: receiverId,
); );
currentMessagesForAds.add(chatMessageModel); currentMessagesForGeneralChat.add(chatMessageModel);
notifyListeners(); notifyListeners();
if (AppState().currentAppType == AppType.customer) {} else {} if (AppState().currentAppType == AppType.customer) {
} else {}
return true; return true;
} }
return false; return false;

@ -1,15 +1,10 @@
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart'; import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/user_models/image_response.dart'; import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';

@ -1,20 +1,20 @@
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/repositories/payments_repo.dart'; import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/services/payments_service.dart'; import 'package:mc_common_app/services/payments_service.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.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/dashboard_view_model_customer.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; import 'package:mc_common_app/view_models/subscriptions_view_model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import '../classes/app_state.dart';
class PaymentVM extends ChangeNotifier { class PaymentVM extends ChangeNotifier {
final PaymentService paymentService; final PaymentService paymentService;
@ -47,6 +47,7 @@ class PaymentVM extends ChangeNotifier {
void updateAppointmentIdsForPayment({required List<int> ids}) { void updateAppointmentIdsForPayment({required List<int> ids}) {
appointmentIdsForPayment = ids; appointmentIdsForPayment = ids;
log("appointmentIdsForPayment: ${appointmentIdsForPayment}");
} }
updateSelectedPaymentMethod(PaymentMethods selectedMethod) { updateSelectedPaymentMethod(PaymentMethods selectedMethod) {
@ -57,62 +58,43 @@ class PaymentVM extends ChangeNotifier {
Future<void> onContinuePressed(BuildContext context, {required PaymentTypes paymentType}) async { Future<void> onContinuePressed(BuildContext context, {required PaymentTypes paymentType}) async {
switch (selectedPaymentMethod) { switch (selectedPaymentMethod) {
case PaymentMethods.mada: case PaymentMethods.mada:
// TODO: Handle this case.
break; break;
case PaymentMethods.visa: case PaymentMethods.visa:
await onVisaCardSelected(context, paymentType); await onVisaCardSelected(context, paymentType);
break; break;
case PaymentMethods.applePay: case PaymentMethods.applePay:
// TODO: Handle this case.
break; break;
case PaymentMethods.masterCard: case PaymentMethods.masterCard:
// TODO: Handle this case.
break; break;
case PaymentMethods.tamara: case PaymentMethods.tamara:
// TODO: Handle this case.
break; break;
} }
return; return;
} }
Future<void> onAdsPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async { Future<void> verifyPayments({required BuildContext context, required int id, List<int>? appointmentIds, required int paymentTypeId, required Function() onVerified, bool isForAppointment = false}) async {
try {
Utils.showLoading(context); Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId); bool isPaid = await paymentRepo.verifyPayment(
await Future.delayed(const Duration(seconds: 2)); paymentTypeId: paymentTypeId,
id: id,
isForAppointments: isForAppointment,
appointmentIds: appointmentIds,
);
Utils.hideLoading(context); Utils.hideLoading(context);
log("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}"); if (!isPaid) {
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentFailed.tr()); Utils.showToast(LocaleKeys.paymentFailed.tr());
pop(context);
return; return;
} }
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentSuccessful.tr()); Utils.showToast(LocaleKeys.paymentSuccessful.tr());
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); onVerified();
} } catch (e) {
} Utils.showToast(e.toString());
Future<void> onAppointmentPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async {
Utils.showLoading(context);
//TODO: CONFIRM FROM ZAHOOR THAT WILL THIS METHOD WORK FOR APPOINTMENT
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
log("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentFailed.tr());
return; return;
} }
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentSuccessful.tr());
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
} }
int getIdTypeByPaymentType(PaymentTypes paymentTypes) { int getIdTypeByPaymentType(PaymentTypes paymentTypes) {
@ -141,66 +123,58 @@ class PaymentVM extends ChangeNotifier {
Utils.showToast(LocaleKeys.paymentFailed.tr()); Utils.showToast(LocaleKeys.paymentFailed.tr());
switch (paymentTypeEnum) { switch (paymentTypeEnum) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
// TODO: Handle this case. case PaymentTypes.appointment:
Utils.showToast("Appointment Payment has been Failed!!");
break;
case PaymentTypes.request:
// TODO: Handle this case.
Utils.showToast("Request Payment has been Failed!!");
break;
case PaymentTypes.adReserve: case PaymentTypes.adReserve:
// TODO: Handle this case.
Utils.showToast("adReserve Payment has been Failed!!");
break;
case PaymentTypes.ads: case PaymentTypes.ads:
// TODO: Handle this case. case PaymentTypes.request:
Utils.showToast("ads Payment has been Failed!!");
break;
case PaymentTypes.extendAds: case PaymentTypes.extendAds:
// TODO: Handle this case.
Utils.showToast("extendAds Payment has been Failed!!");
break;
case PaymentTypes.appointment:
// TODO: Handle this case.
Utils.showToast("Appointment Payment has been Failed!!");
break;
case PaymentTypes.partialAppointment: case PaymentTypes.partialAppointment:
Utils.showToast("partialAppointment Payment has been Failed!!");
break; break;
} }
}, },
onSuccess: () async { onSuccess: () async {
// TOD0: we have to take payment confirmation methods from Backend team and make success callbacks like onAdsPaymentSuccess Utils.showToast("Verifying Payment..");
switch (paymentTypeEnum) { switch (paymentTypeEnum) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
onSubscriptionPaymentSuccess(context); await verifyPayments(
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: orderProviderSubscriptionId,
onVerified: () => onSubscriptionPaymentSuccess(context),
);
break; break;
case PaymentTypes.appointment: case PaymentTypes.appointment:
Utils.showToast("Appointment Payment has been Succeeded");
break;
case PaymentTypes.partialAppointment: case PaymentTypes.partialAppointment:
Utils.showToast("Partial Appointment Payment has been Succeeded"); await verifyPayments(
id: 0,
isForAppointment: true,
appointmentIds: appointmentIdsForPayment,
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
onVerified: () => onAppointmentSuccess(context),
);
break; break;
case PaymentTypes.request: case PaymentTypes.request:
Utils.showToast("Request Payment has been Succeeded"); await verifyPayments(
onRequestPaymentSuccess(context); context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: requestId,
onVerified: () => onRequestPaymentSuccess(context),
);
break; break;
case PaymentTypes.adReserve: case PaymentTypes.adReserve:
case PaymentTypes.ads: case PaymentTypes.ads:
case PaymentTypes.extendAds: case PaymentTypes.extendAds:
await onAdsPaymentSuccess(context: context, paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(), currentAdId: currentAdId); await verifyPayments(
break; context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: currentAdId,
onVerified: () => onAdsPaymentSuccess(context),
);
} }
}, },
); );
@ -208,15 +182,22 @@ class PaymentVM extends ChangeNotifier {
void onRequestPaymentSuccess(BuildContext context) { void onRequestPaymentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(4); context.read<DashboardVmCustomer>().onNavbarTapped(4);
navigateReplaceWithName(context, AppRoutes.dashboard); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
} }
onSubscriptionPaymentSuccess(BuildContext context) { void onAdsPaymentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(3);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
void onSubscriptionPaymentSuccess(BuildContext context) {
pop(context); pop(context);
// context.read<SubscriptionsVM>().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
// context.read<SubscriptionsVM>().getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); // context.read<SubscriptionsVM>().getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true);
// context.read<SubscriptionsVM>().mySubscriptionsBySp = []; navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
// context.read<SubscriptionsVM>().getMySubscriptionsBySP(); }
void onAppointmentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
} }

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
@ -93,6 +94,14 @@ class ServiceVM extends BaseVM {
Future<void> getServiceProviderDocument(int providerId) async { Future<void> getServiceProviderDocument(int providerId) async {
setState(ViewState.busy); setState(ViewState.busy);
document = await branchRepo.getServiceProviderDocument(providerId); document = await branchRepo.getServiceProviderDocument(providerId);
if (document != null && document!.data != null && document!.data!.isNotEmpty) {
for (var doc in document!.data!) {
log("doc: ${doc.status}");
if (doc.status != 3) {
updateIsAllDocsApproved(false);
}
}
}
setState(ViewState.idle); setState(ViewState.idle);
} }
@ -121,7 +130,6 @@ class ServiceVM extends BaseVM {
filterUserBranchCategories() { filterUserBranchCategories() {
categories = []; categories = [];
print("Filter Branch Executed");
List<BranchDetailModel>? localbranches; List<BranchDetailModel>? localbranches;
if (branches!.data != null) { if (branches!.data != null) {
if (selectedBranchStatus == 3) { if (selectedBranchStatus == 3) {
@ -202,13 +210,20 @@ class ServiceVM extends BaseVM {
// return null; // return null;
// } // }
bool isAllDocsApproved = false;
updateIsAllDocsApproved(var value) {
isAllDocsApproved = value;
notifyListeners();
}
Future<void> pickPdfReceiptFile(BuildContext context, int documentID, int index) async { Future<void> pickPdfReceiptFile(BuildContext context, int documentID, int index) async {
List<ImageModel> imageModels = []; List<ImageModel> imageModels = [];
List<File>? files = await commonServices.pickMultipleFiles( List<File>? files = await commonServices.pickMultipleFiles(
context, context,
allowMultiple: false, allowMultiple: false,
); );
if (files == null) return null; if (files == null) return;
for (var element in files) { for (var element in files) {
imageModels.add(ImageModel( imageModels.add(ImageModel(
filePath: element.path, filePath: element.path,
@ -236,16 +251,6 @@ class ServiceVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
Future<void> removeNetworkImag(String filePath) async {
int index = document!.data!.indexWhere((element) => element.documentUrl == filePath);
if (index == -1) {
return;
}
document!.data![index].documentUrl = null;
document!.data![index].isLocalFile = true;
notifyListeners();
}
Future<void> commercialRemove(String filePath) async { Future<void> commercialRemove(String filePath) async {
int index = commercialCertificates.indexWhere((element) => element.filePath == filePath); int index = commercialCertificates.indexWhere((element) => element.filePath == filePath);
if (index == -1) { if (index == -1) {
@ -264,6 +269,16 @@ class ServiceVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
Future<void> removeNetworkImage(String filePath) async {
int index = document!.data!.indexWhere((element) => element.documentUrl == filePath);
if (index == -1) {
return;
}
document!.data![index].documentUrl = null;
document!.data![index].isLocalFile = true;
notifyListeners();
}
Future<GenericRespModel> updateDocument(List<DocumentData>? data) async { Future<GenericRespModel> updateDocument(List<DocumentData>? data) async {
return await branchRepo.serviceProviderDocumentsUpdate(data); return await branchRepo.serviceProviderDocumentsUpdate(data);
} }
@ -272,8 +287,11 @@ class ServiceVM extends BaseVM {
Future<void> getBranchAndServices() async { Future<void> getBranchAndServices() async {
setState(ViewState.busy); setState(ViewState.busy);
branches = await branchRepo.getBranchAndServices(); branches = await branchRepo.getBranchAndServices();
if (branches!.data != null) if (branches!.data == null) {
homePageBranches = [];
} else {
homePageBranches = branches!.data!.serviceProviderBranch!.where((element) => element.branchStatus == BranchStatusEnum.approvedOrActive).toList(); homePageBranches = branches!.data!.serviceProviderBranch!.where((element) => element.branchStatus == BranchStatusEnum.approvedOrActive).toList();
}
setState(ViewState.idle); setState(ViewState.idle);
} }
@ -405,6 +423,7 @@ class ServiceVM extends BaseVM {
Future<void> fetchServicesByCategoryId(int categoryId) async { Future<void> fetchServicesByCategoryId(int categoryId) async {
servicesDropList = []; servicesDropList = [];
setState(ViewState.busy); setState(ViewState.busy);
//TODO: here
services = await branchRepo.fetchServicesByCategoryId(serviceCategoryId: categoryId); // to get all the services services = await branchRepo.fetchServicesByCategoryId(serviceCategoryId: categoryId); // to get all the services
for (var element in services!.data!) { for (var element in services!.data!) {
servicesDropList.add( servicesDropList.add(
@ -575,9 +594,7 @@ class ServiceVM extends BaseVM {
File file = File(imageModel.filePath!); File file = File(imageModel.filePath!);
List<int> imageBytes = await file.readAsBytes(); List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes); String image = base64Encode(imageBytes);
String fileName = file.path String fileName = file.path.split('/').last;
.split('/')
.last;
branchPostingImages = BranchPostingImages( branchPostingImages = BranchPostingImages(
imageName: fileName, imageName: fileName,
imageStr: image, imageStr: image,
@ -622,8 +639,8 @@ class ServiceVM extends BaseVM {
GenericRespModel res = await branchRepo.createBranch( GenericRespModel res = await branchRepo.createBranch(
branchName: branchName, branchName: branchName,
branchDescription: branchDesc, branchDescription: branchDesc,
openTime: branchDesc, openTime: openTime,
closeTime: branchDesc, closeTime: closeTime,
cityId: cityID, cityId: cityID,
address: address, address: address,
latitude: latitude, latitude: latitude,
@ -657,6 +674,14 @@ class ServiceVM extends BaseVM {
required String latitude, required String latitude,
required String longitude, required String longitude,
}) async { }) async {
// log(branchName);
// log(branchDesc);
// log(openTime);
// log(closedTime);
// log(cityID.toString());
// log(address);
// log(latitude);
// log(longitude);
if (branchName.isEmpty || branchDesc.isEmpty || address.isEmpty) { if (branchName.isEmpty || branchDesc.isEmpty || address.isEmpty) {
branchErrorScreen = GlobalConsts.fillAllFields; branchErrorScreen = GlobalConsts.fillAllFields;
notifyListeners(); notifyListeners();

@ -0,0 +1,59 @@
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.dart';
import 'package:mc_common_app/repositories/setting_options_repo.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
class SettingOptionsVM extends BaseVM {
final SettingOptionsRepo settingOptionsRepo;
SettingOptionsVM({required this.settingOptionsRepo});
List<FAQsModel> faqsList = [];
Future<void> getAllFaqs() async {
setState(ViewState.busy);
try {
faqsList = await settingOptionsRepo.getAllFaqs();
setState(ViewState.idle);
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
setState(ViewState.idle);
}
}
List<ContactInfoModel> contactInfosList = [];
Future<void> getAllContactInfosList() async {
setState(ViewState.busy);
try {
contactInfosList = await settingOptionsRepo.getAllContactInfos();
setState(ViewState.idle);
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
setState(ViewState.idle);
}
}
List<AppInfoModel> appInfoList = [];
Future<void> getAppInfoList() async {
setState(ViewState.busy);
try {
appInfoList = await settingOptionsRepo.getAppInfoList();
setState(ViewState.idle);
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
setState(ViewState.idle);
}
}
}

@ -0,0 +1,110 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.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';
import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/shipping_repo.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
class ShippingManagementVM extends BaseVM {
final ShippingRepo shippingRepo;
final CommonRepo commonRepo;
ShippingManagementVM({required this.shippingRepo, required this.commonRepo});
List<ShippingRequestModel> shippingRequestsList = [];
List<EnumsModel> shippingStatusEnums = [];
List<FilterListModel> shippingRequestFilterOptions = [];
List<FilterListModel> shippingRequestStatusesList = [];
String requestStatusComments = "";
void updateRequestStatusComments(var value) {
requestStatusComments = value;
}
resetFilters() {
if (shippingRequestFilterOptions.isEmpty) return;
for (var value in shippingRequestFilterOptions) {
value.isSelected = false;
}
shippingRequestFilterOptions[0].isSelected = true;
requestStatusComments = "";
}
Future<void> populateShippingRequestFilterList() async {
if (shippingRequestFilterOptions.isNotEmpty && shippingRequestStatusesList.isNotEmpty) return;
shippingStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.shippingStatusEnumId);
shippingRequestFilterOptions.clear();
shippingRequestStatusesList.clear();
for (int i = 0; i < shippingStatusEnums.length; i++) {
shippingRequestFilterOptions.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue));
shippingRequestStatusesList.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue));
}
shippingRequestFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(0.toShippingStatusEnum()), isSelected: true, id: 0));
notifyListeners();
}
Future<void> applyFiltersOnShippingRequests({required ShippingRequestStatusEnum shippingRequestStatusEnum}) async {
for (var value in shippingRequestFilterOptions) {
value.isSelected = false;
}
if (shippingRequestStatusEnum == ShippingRequestStatusEnum.allRequests) {
shippingRequestFilterOptions[0].isSelected = true;
await getShippingRequestsListByFilters();
notifyListeners();
return;
}
shippingRequestFilterOptions[shippingRequestStatusEnum.getIdFromShippingStatusEnum()].isSelected = true; // -1 to match with the index
await getShippingRequestsListByFilters(shippingStatusEnum: shippingRequestStatusEnum);
notifyListeners();
}
void updateSelectionInShippingRequestStatuses(int index) {
for (var value in shippingRequestStatusesList) {
value.isSelected = false;
}
shippingRequestStatusesList[index].isSelected = true;
notifyListeners();
}
Future<void> getShippingRequestsListByFilters({ShippingRequestStatusEnum? shippingStatusEnum}) async {
setState(ViewState.busy);
try {
shippingRequestsList = await shippingRepo.getShippingRequestListByStatus(shippingStatusEnum: shippingStatusEnum);
setState(ViewState.idle);
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
setState(ViewState.idle);
}
}
Future<bool> onUpdateShippingStatusTapped({required BuildContext context, required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId}) async {
Utils.showLoading(context);
try {
GenericRespModel? genericRespModel = await shippingRepo.updateShippingRequestStatus(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId);
Utils.showToast(genericRespModel.message.toString());
Utils.hideLoading(context);
return genericRespModel.messageStatus == 1;
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
return false;
}
}
}

@ -1,10 +1,6 @@
import 'dart:convert';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/subscriptions_models/branch_user_selection_model.dart'; import 'package:mc_common_app/models/subscriptions_models/branch_user_selection_model.dart';
import 'package:mc_common_app/models/subscriptions_models/provider_subscription_model.dart';
import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart'; import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:mc_common_app/view_models/base_view_model.dart';
@ -118,12 +114,7 @@ class SubscriptionsVM extends BaseVM {
} }
Future<GenericRespModel> createSubscriptionOrder(int subscriptionId, bool isStartNow, bool isRenew, {bool isDegrade = false, List<int>? listOfBranches, List<int>? listOfUsers}) async { Future<GenericRespModel> createSubscriptionOrder(int subscriptionId, bool isStartNow, bool isRenew, {bool isDegrade = false, List<int>? listOfBranches, List<int>? listOfUsers}) async {
Map<String, dynamic> map = { Map<String, dynamic> map = {"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "", "subscriptionID": subscriptionId.toString(), "isStartNow": isStartNow.toString(), "isRenew": isRenew.toString()};
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"subscriptionID": subscriptionId.toString(),
"isStartNow": isStartNow.toString(),
"isRenew": isRenew.toString()
};
GenericRespModel genericRespModel = await subscriptionRepo.payForProviderSubscription(map); GenericRespModel genericRespModel = await subscriptionRepo.payForProviderSubscription(map);
return genericRespModel; return genericRespModel;
} }

@ -264,11 +264,13 @@ class VehicleDetails extends StatelessWidget {
28.height, 28.height,
LocaleKeys.vehiclePictures.tr().toText(fontSize: 18, isBold: true), LocaleKeys.vehiclePictures.tr().toText(fontSize: 18, isBold: true),
8.height, 8.height,
if (adVM.pickedPostingImages.isEmpty) ...[
DottedRectContainer( DottedRectContainer(
onTap: () => context.read<AdVM>().pickMultipleImages(), onTap: () => context.read<AdVM>().pickMultipleImages(),
text: LocaleKeys.attachImage.tr(), text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(), icon: MyAssets.attachmentIcon.buildSvg(),
), ),
],
if (adVM.vehicleImageError != "") ...[ if (adVM.vehicleImageError != "") ...[
10.height, 10.height,
Row( Row(

@ -57,7 +57,7 @@ class AdsBuyerChatsView extends StatelessWidget {
(chatForAdsModel.buyerName ?? "").toText(fontSize: 16, isBold: true), (chatForAdsModel.buyerName ?? "").toText(fontSize: 16, isBold: true),
if (chatForAdsModel.unReadMessagesCount != null && chatForAdsModel.unReadMessagesCount! > 0) ...[ if (chatForAdsModel.unReadMessagesCount != null && chatForAdsModel.unReadMessagesCount! > 0) ...[
Center( Center(
child: "${chatForAdsModel.unReadMessagesCount ?? "1"}".toText( child: "${chatForAdsModel.unReadMessagesCount}".toText(
color: Colors.white, color: Colors.white,
isBold: true, isBold: true,
fontSize: 10, fontSize: 10,

@ -7,6 +7,7 @@ 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/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.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/theme/colors.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
@ -271,10 +272,40 @@ class _AdsDetailViewState extends State<AdsDetailView> {
}).toWhiteContainer(width: double.infinity, allPading: 12); }).toWhiteContainer(width: double.infinity, allPading: 12);
} }
Widget buildAdStartEndDates() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
("${LocaleKeys.startDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
widget.adDetails.startdate != null
? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.startdate!)).toText(
fontSize: 10,
)
: const SizedBox(),
],
),
Row(
children: [
("${LocaleKeys.endDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
widget.adDetails.enddate != null
? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.enddate!)).toText(
fontSize: 10,
)
: const SizedBox(),
],
),
],
).paddingOnly(top: 5, bottom: 5).onPress(() {
showMyBottomSheet(context, child: AdDamagePartPicturesSheet(adDamageReportList: widget.adDetails.vehicle!.damagereport ?? []));
}).toWhiteContainer(width: double.infinity, allPading: 12);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget actionWidget = const SizedBox(); Widget actionWidget = const SizedBox();
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active)) { if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active) && (widget.adDetails.adPostStatus != AdPostStatus.pendingForPost)) {
actionWidget = IconButton( actionWidget = IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor), icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () { onPressed: () {
@ -318,6 +349,10 @@ class _AdsDetailViewState extends State<AdsDetailView> {
if (widget.adDetails.vehicle!.damagereport != null && widget.adDetails.vehicle!.damagereport!.isNotEmpty) ...[ if (widget.adDetails.vehicle!.damagereport != null && widget.adDetails.vehicle!.damagereport!.isNotEmpty) ...[
buildDamagePartDetails(), buildDamagePartDetails(),
], ],
if (widget.adDetails.isMyAd ?? false) ...[
12.height,
buildAdStartEndDates(),
],
12.height, 12.height,
if (widget.adDetails.adPostStatus == AdPostStatus.rejected) ...[ if (widget.adDetails.adPostStatus == AdPostStatus.rejected) ...[
buildAdRejectionDetails(), buildAdRejectionDetails(),
@ -329,6 +364,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
child: Column( child: Column(
children: [ children: [
if (!(widget.adDetails.isMyAd ?? false)) ...[ if (!(widget.adDetails.isMyAd ?? false)) ...[
const Divider(thickness: 1, height: 1),
const Divider(thickness: 1, height: 1), const Divider(thickness: 1, height: 1),
18.height, 18.height,
Row( Row(

@ -7,6 +7,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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.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/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
@ -19,6 +20,7 @@ import 'package:mc_common_app/views/advertisement/components/picked_images_conta
import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart'; import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart'; import 'package:mc_common_app/widgets/bottom_sheet.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
@ -277,11 +279,11 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) { return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return InfoBottomSheet( return InfoBottomSheet(
title: LocaleKeys.setDateandTime.tr().toText(fontSize: 16, isBold: true, letterSpacing: -1.44, height: 1.2), title: LocaleKeys.setDateandTime.tr().toText(fontSize: 16, height: 1.2),
description: Column( description: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
25.height, 20.height,
adVM.state == ViewState.busy adVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: Builder( : Builder(
@ -343,7 +345,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
], ],
), ),
], ],
19.height, 30.height,
], ],
)); ));
}); });
@ -496,11 +498,11 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
} }
Widget pendingForReviewAction({required String pendingText}) { Widget pendingForReviewAction({required String pendingText}) {
bool isForShippingOrDelivery = false; bool isForShippingOrDelivery = true;
return Center( return Center(
child: pendingText.toText( child: pendingText.toText(
color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor, color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor,
fontSize: isForShippingOrDelivery ? 14 : 16, fontSize: isForShippingOrDelivery ? 15 : 16,
// isItalic: true, // isItalic: true,
), ),
).toContainer( ).toContainer(
@ -512,22 +514,6 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
); );
} }
Widget buildStatusContainer(String text, {bool isForShippingOrDelivery = true}) {
return Center(
child: text.toText(
color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor,
fontSize: isForShippingOrDelivery ? 14 : 16,
// isItalic: true,
),
).toContainer(
marginAll: 12,
paddingAll: 12,
borderRadius: 8,
width: double.infinity,
backgroundColor: isForShippingOrDelivery ? MyColors.grey98Color.withOpacity(0.1) : MyColors.adPendingStatusColor.withOpacity(0.16),
);
}
Widget pendingForPaymentAction(BuildContext context, {required AdDetailsModel ad}) { Widget pendingForPaymentAction(BuildContext context, {required AdDetailsModel ad}) {
SpecialServiceModelForAds? photoSpecialServiceModel; SpecialServiceModelForAds? photoSpecialServiceModel;
for (var element in ad.specialservice!) { for (var element in ad.specialservice!) {
@ -592,11 +578,38 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
maxHeight: 55, maxHeight: 55,
title: LocaleKeys.markAsSold.tr(), title: LocaleKeys.markAsSold.tr(),
isBold: false, isBold: false,
onPressed: () {
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.markAsSold.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.markAsSold.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () { onPressed: () {
adVM.markAdAsSold(context, adId: adDetailsModel.id!); adVM.markAdAsSold(context, adId: adDetailsModel.id!);
}, },
), ),
), ),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
},
),
),
], ],
), ),
8.height, 8.height,
@ -610,6 +623,88 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
title: LocaleKeys.deactivateAd.tr(), title: LocaleKeys.deactivateAd.tr(),
txtColor: MyColors.redColor, txtColor: MyColors.redColor,
onPressed: () { onPressed: () {
buildAdDeactivateReasonsBottomSheet(context, adDetails: adDetailsModel);
},
),
),
],
),
],
);
}
Future buildAdDeactivateReasonsBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return InfoBottomSheet(
title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
ListView.separated(
shrinkWrap: true,
itemCount: adVM.deActivateAdModelList.length,
separatorBuilder: (BuildContext context, int index) {
if (adVM.deActivateAdModelList[index].index == 3) {
return const SizedBox();
}
return const Divider(thickness: 0.5);
},
itemBuilder: (BuildContext context, int index) {
if (adVM.deActivateAdModelList[index].index == 3) {
return const SizedBox();
}
OfferRequestCommentModel offerRequestCommentModel = adVM.deActivateAdModelList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
adVM.updateSelectionInDeActivateAdModelList(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) ...[
// comparing if the "other" is selected
12.height,
TxtField(
maxLines: 5,
value: adVM.deactivateAdReasonDescription,
errorValue: adVM.deactivateAdReasonDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.reason.tr(),
onChanged: (v) => adVM.updateDeactivateAdReasonDescription(v),
),
],
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () {
String comments = "";
if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) //Other
{
comments = adVM.deactivateAdReasonDescription;
} else {
comments = adVM.selectedDeActivateAdCommentModel.title ?? "";
}
if (!adVM.isDeActivateReasonSubmitValidated()) {
return;
}
return actionConfirmationBottomSheet( return actionConfirmationBottomSheet(
context: context, context: context,
title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
@ -620,8 +715,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
title: LocaleKeys.yes.tr(), title: LocaleKeys.yes.tr(),
fontSize: 15, fontSize: 15,
onPressed: () { onPressed: () {
Navigator.pop(context); adVM.deactivateTheAd(context, adId: adDetailsModel.id!, comment: comments);
adVM.deactivateTheAd(context, adId: adDetailsModel.id!);
}, },
), ),
), ),
@ -640,11 +734,14 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
), ),
); );
}, },
maxWidth: double.infinity,
), ),
), 19.height,
], ],
), ),
], ));
});
},
); );
} }
@ -947,6 +1044,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
case AdPostStatus.rejected: case AdPostStatus.rejected:
return pendingForReviewAction(pendingText: LocaleKeys.rejectedFormAdmin.tr()); return pendingForReviewAction(pendingText: LocaleKeys.rejectedFormAdmin.tr());
case AdPostStatus.cancelled: case AdPostStatus.cancelled:
return pendingForReviewAction(pendingText: LocaleKeys.cancelledByOwner.tr());
case AdPostStatus.pendingForPost: case AdPostStatus.pendingForPost:
return pendingForReviewAction(pendingText: LocaleKeys.waitingAdminPost.tr()); return pendingForReviewAction(pendingText: LocaleKeys.waitingAdminPost.tr());

@ -30,6 +30,7 @@ class AdsListWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (isAdsFragment && adsList.isEmpty) { if (isAdsFragment && adsList.isEmpty) {
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -137,9 +138,7 @@ class AdCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
(adDetails.vehicle!.cityName ?? "").toText( (adDetails.vehicle!.cityName ?? "").toText(color: MyColors.lightTextColor),
color: MyColors.lightTextColor,
),
adDetails.createdOn != null adDetails.createdOn != null
? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText( ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(
color: MyColors.lightTextColor, color: MyColors.lightTextColor,
@ -159,7 +158,7 @@ class AdCard extends StatelessWidget {
children: [ children: [
(adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 19, isBold: true, letterSpacing: -1.16, height: 29 / 19), (adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 19, isBold: true, letterSpacing: -1.16, height: 29 / 19),
2.width, 2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10), LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10).paddingOnly(bottom: 3),
], ],
), ),
), ),

@ -11,10 +11,11 @@ class PickedFilesContainer extends StatelessWidget {
final Function(String filePath)? onCrossPressedPrimary; final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary; final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index; final int? index;
final Function() onAddFilePressed;
final bool isReview; final bool isReview;
final bool isPdf; final bool isPdf;
final bool isFromNetwork; final bool isFromNetwork;
final Function() onAddFilePressed; final bool allowAdButton;
const PickedFilesContainer({ const PickedFilesContainer({
Key? key, Key? key,
@ -26,6 +27,7 @@ class PickedFilesContainer extends StatelessWidget {
this.isReview = false, this.isReview = false,
this.isPdf = false, this.isPdf = false,
this.isFromNetwork = false, this.isFromNetwork = false,
this.allowAdButton = true,
}) : super(key: key); }) : super(key: key);
@override @override
@ -37,9 +39,13 @@ class PickedFilesContainer extends StatelessWidget {
crossAxisSpacing: 4.0, crossAxisSpacing: 4.0,
mainAxisSpacing: 8.0, mainAxisSpacing: 8.0,
children: List.generate( children: List.generate(
isReview ? pickedFiles.length : pickedFiles.length + 1, !allowAdButton
? pickedFiles.length
: (isReview)
? pickedFiles.length
: pickedFiles.length + 1,
(index) { (index) {
if (index == pickedFiles.length && !isReview) { if (index == pickedFiles.length && !isReview && allowAdButton) {
return Container( return Container(
decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)), decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)),
margin: const EdgeInsets.all(8), margin: const EdgeInsets.all(8),
@ -107,20 +113,22 @@ class BuildFilesContainer extends StatelessWidget {
child: const Icon(Icons.picture_as_pdf).paddingAll(8), child: const Icon(Icons.picture_as_pdf).paddingAll(8),
) )
: image.isFromNetwork! : image.isFromNetwork!
? Image.network( ? image.filePath!
image.filePath!, .buildNetworkImage(
fit: BoxFit.fill, fit: BoxFit.fill,
height: 75, height: 75,
width: 73, width: 73,
).paddingAll(8) )
: Image.file( .paddingAll(8)
File(image.filePath!), : image.filePath!
.buildFileImage(
fit: BoxFit.fill, fit: BoxFit.fill,
height: 72, height: 72,
width: 70, width: 70,
).paddingAll(8), )
!isReview .paddingAll(8),
? Align( if (!isReview) ...[
Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: MyAssets.closeWithOrangeBg.buildSvg( child: MyAssets.closeWithOrangeBg.buildSvg(
fit: BoxFit.fill, fit: BoxFit.fill,
@ -134,7 +142,7 @@ class BuildFilesContainer extends StatelessWidget {
} }
onCrossPressedPrimary!(image.filePath!); onCrossPressedPrimary!(image.filePath!);
}) })
: const SizedBox() ]
], ],
)), )),
], ],

@ -1,6 +1,7 @@
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; 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/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
@ -46,6 +47,14 @@ class SelectAdTypeView extends StatelessWidget {
if (arguments.length > 2) { if (arguments.length > 2) {
adsId = arguments[2] ?? -1; adsId = arguments[2] ?? -1;
} }
int totalAds = 0;
int remainingAds = 0;
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.adsRemaining != null) {
totalAds = AppState().getproviderSubscription.first.totalAds ?? 0;
remainingAds = AppState().getproviderSubscription.first.adsRemaining ?? 0;
}
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.selectAdType.tr(), title: LocaleKeys.selectAdType.tr(),
@ -138,7 +147,7 @@ class SelectAdTypeView extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
"5 of 10 ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1), "$remainingAds of $totalAds ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1),
LocaleKeys.adsRemainingVar.tr().toText(fontSize: 17, color: MyColors.lightTextColor, isBold: true), LocaleKeys.adsRemainingVar.tr().toText(fontSize: 17, color: MyColors.lightTextColor, isBold: true),
], ],
), ),

@ -8,6 +8,7 @@ import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/app_bar.dart';
@ -15,6 +16,7 @@ import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart'
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:sizer/sizer.dart';
class AppointmentDetailView extends StatelessWidget { class AppointmentDetailView extends StatelessWidget {
final AppointmentListModel appointmentListModel; final AppointmentListModel appointmentListModel;
@ -43,15 +45,9 @@ class AppointmentDetailView extends StatelessWidget {
case AppointmentPaymentStatusEnum.payPartial: case AppointmentPaymentStatusEnum.payPartial:
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: SizedBox(
children: [ height: 8.h,
getBaseActionButtonWidget( child: Utils.buildStatusContainer(LocaleKeys.workInProgress.tr()),
color: MyColors.grey98Color.withOpacity(0.1),
textColor: MyColors.lightTextColor,
onPressed: () {},
text: LocaleKeys.workInProgress.tr(),
),
],
), ),
); );
case AppointmentPaymentStatusEnum.payNow: case AppointmentPaymentStatusEnum.payNow:
@ -85,7 +81,7 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
children: [ children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: LocaleKeys.cancel.tr()),
12.width, 12.width,
getBaseActionButtonWidget( getBaseActionButtonWidget(
color: MyColors.greenColor, color: MyColors.greenColor,
@ -108,15 +104,9 @@ class AppointmentDetailView extends StatelessWidget {
case AppointmentStatusEnum.visitCompleted: case AppointmentStatusEnum.visitCompleted:
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: SizedBox(
children: [ height: 8.h,
getBaseActionButtonWidget( child: Utils.buildStatusContainer(LocaleKeys.visitCompleted.tr()),
color: MyColors.grey98Color.withOpacity(0.3),
textColor: MyColors.lightTextColor,
onPressed: () {},
text: LocaleKeys.visitCompleted.tr(),
),
],
), ),
); );
@ -126,20 +116,19 @@ class AppointmentDetailView extends StatelessWidget {
case AppointmentStatusEnum.cancelled: case AppointmentStatusEnum.cancelled:
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: SizedBox(
children: [ height: 8.h,
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"), child: Utils.buildStatusContainer(LocaleKeys.appointmentCancelled.tr()),
],
), ),
); );
case AppointmentStatusEnum.allAppointments: case AppointmentStatusEnum.allAppointments:
return SizedBox(); return const SizedBox();
case AppointmentStatusEnum.rescheduled: case AppointmentStatusEnum.rescheduled:
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
children: [ children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: LocaleKeys.cancel.tr()),
12.width, 12.width,
getBaseActionButtonWidget( getBaseActionButtonWidget(
color: MyColors.greenColor, color: MyColors.greenColor,
@ -151,7 +140,7 @@ class AppointmentDetailView extends StatelessWidget {
), ),
); );
default: default:
return SizedBox(); return const SizedBox();
} }
} }
@ -224,20 +213,14 @@ class AppointmentDetailView extends StatelessWidget {
Column( Column(
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) { children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
ServiceModel service = appointmentListModel.appointmentServicesList![index]; ServiceModel service = appointmentListModel.appointmentServicesList![index];
return Column( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// MyAssets.maintenanceIcon.buildSvg(
// height: 10,
// width: 10,
// fit: BoxFit.fill,
// ),
// 10.width,
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true), "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true),
],
),
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[ if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
Column( Column(
children: List.generate( children: List.generate(
@ -250,18 +233,20 @@ class AppointmentDetailView extends StatelessWidget {
), ),
).paddingOnly(left: 15), ).paddingOnly(left: 15),
], ],
],
),
5.height, 5.height,
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true), ((service.currentTotalServicePrice).toString()).toText(fontSize: 19, isBold: true),
2.width, 2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 5),
const Icon(Icons.arrow_drop_down, size: 30) const Icon(Icons.arrow_drop_down, size: 25)
], ],
).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)), ).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)),
], ],
); ).paddingOnly(bottom: 15);
}), }),
), ),
], ],

@ -5,6 +5,7 @@ import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart'; import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
@ -62,7 +63,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), (LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(scheduleData.appointmentType == 2 ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(), (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(),
], ],
), ),
Column( Column(

@ -65,6 +65,7 @@ class BookAppointmentServicesView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), (LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
4.width,
(serviceData.isHomeSelected ? serviceData.homeLocation : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(), (serviceData.isHomeSelected ? serviceData.homeLocation : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(),
], ],
), ),

@ -49,15 +49,16 @@ class BookAppointmentsItemView extends StatelessWidget {
children: [ children: [
LocaleKeys.workshopFullAccessServices.tr().toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor), LocaleKeys.workshopFullAccessServices.tr().toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor),
8.height, 8.height,
Row( // Row(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
LocaleKeys.changeLocationService.tr().toText(fontSize: 14, isBold: true), // LocaleKeys.changeLocationService.tr().toText(fontSize: 14, isBold: true),
LocaleKeys.edit.tr().toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor), // 5.width,
5.width, // LocaleKeys.edit.tr().toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor),
MyAssets.icEdit.buildSvg(width: 17), // 5.width,
], // MyAssets.icEdit.buildSvg(width: 17),
).onPress(() {}), // ],
// ).onPress(() {}),
16.height, 16.height,
const Divider(), const Divider(),
], ],

@ -8,6 +8,7 @@ import 'package:mc_common_app/models/appointments_models/service_schedule_model.
import 'package:mc_common_app/models/services_models/item_model.dart'; import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/app_bar.dart';
@ -160,7 +161,7 @@ class ReviewAppointment extends StatelessWidget {
]), ]),
Row(children: [ Row(children: [
("${LocaleKeys.location.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), ("${LocaleKeys.location.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(scheduleData.appointmentType == 2 ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true), (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true),
]), ]),
], ],
), ),
@ -184,7 +185,7 @@ class ReviewAppointment extends StatelessWidget {
"${scheduleData.amountTotal.toString()} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true), "${scheduleData.amountTotal.toString()} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true),
], ],
), ),
if (scheduleData.appointmentType == 1) ...[ if (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home) ...[
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -217,7 +218,7 @@ class ReviewAppointment extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Divider(thickness: 0.7, height: 3), const Divider(thickness: 0.7, height: 3),
8.height, 8.height,
if (appointmentsVM.amountToPayForAppointment > 0) ...[ if (appointmentsVM.amountToPayForAppointment > 0) ...[
Row( Row(

@ -8,6 +8,7 @@ import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart'; import 'package:mc_common_app/views/location_views/pick_location_page.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
@ -94,7 +95,13 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
maxHeight: 48, maxHeight: 48,
title: LocaleKeys.home.tr(), title: LocaleKeys.home.tr(),
txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor,
onPressed: () => appointmentsVM.updateIsHomeTapped(true), onPressed: () {
if (appointmentsVM.currentServiceSelection != null && (appointmentsVM.currentServiceSelection!.isAllowAppointmentHome ?? false)) {
appointmentsVM.updateIsHomeTapped(true);
} else {
Utils.showToast("The Selected Service is not available at Home Location.");
}
},
), ),
), ),
12.width, 12.width,
@ -116,8 +123,8 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
errorValue: appointmentsVM.pickHomeLocationError, errorValue: appointmentsVM.pickHomeLocationError,
value: appointmentsVM.pickedHomeLocation, value: appointmentsVM.pickedHomeLocation,
isNeedClickAll: true, isNeedClickAll: true,
postfixData: Icons.location_on, postfixData: Icons.add_location_outlined,
postFixDataColor: MyColors.darkTextColor, postFixDataColor: MyColors.darkPrimaryColor,
onTap: () { onTap: () {
navigateTo( navigateTo(
context, context,
@ -148,14 +155,14 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
width: double.infinity, width: double.infinity,
child: Column( child: Column(
children: [ children: [
if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[ if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices && appointmentsVM.currentServiceSelection != null && (appointmentsVM.currentServiceSelection!.isAllowAppointmentHome ?? false)) ...[
const Divider(thickness: 1, height: 1), const Divider(thickness: 1, height: 1),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
// TODO: This Price will be decided according to the service selected, We will calculate the KMs and multiple it with price per KMs // TODO: This Price will be decided according to the service selected, We will calculate the KMs and multiple it with price per KMs
150.toString().toText(fontSize: 30, isBold: true), appointmentsVM.currentServiceSelection!.rangePricePerKm.toString().toText(fontSize: 30, isBold: true),
LocaleKeys.sar.tr().toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), "${LocaleKeys.sar.tr()}/km".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
], ],
), ),
LocaleKeys.additionalChargesNotice.tr().toText(fontSize: 12, color: MyColors.lightTextColor), LocaleKeys.additionalChargesNotice.tr().toText(fontSize: 12, color: MyColors.lightTextColor),

@ -14,6 +14,7 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/widgets/common_widgets/custom_add_button_widget.dart'; import 'package:mc_common_app/widgets/common_widgets/custom_add_button_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';

@ -50,6 +50,9 @@ class _ChatViewState extends State<ChatView> {
chatViewArgumentsForAd = widget.chatViewArguments.chatViewArgumentsForAd; chatViewArgumentsForAd = widget.chatViewArguments.chatViewArgumentsForAd;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) { } else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
chatViewArgumentsForRequest = widget.chatViewArguments.chatViewArgumentsForRequest; chatViewArgumentsForRequest = widget.chatViewArguments.chatViewArgumentsForRequest;
} else if (chatTypeEnum == ChatTypeEnum.general) {
// For General Chat
chatViewArgumentsForAd = widget.chatViewArguments.chatViewArgumentsForAd;
} }
chatVM = context.read<ChatVM>(); chatVM = context.read<ChatVM>();
chatVM.isUserOnChatScreen = true; chatVM.isUserOnChatScreen = true;
@ -85,7 +88,15 @@ class _ChatViewState extends State<ChatView> {
adId: chatViewArgumentsForAd!.adsID!, adId: chatViewArgumentsForAd!.adsID!,
context: context, context: context,
); );
} else if (chatTypeEnum == ChatTypeEnum.general) {} } else if (chatTypeEnum == ChatTypeEnum.general) {
status = await chatVM.onTextMessageSendForGeneralChat(
receiverId: chatViewArgumentsForAd!.receiverUserID ?? "",
chatMessageType: ChatMessageTypeEnum.freeText,
message: chatVM.chatMessageText,
adId: chatViewArgumentsForAd!.adsID!,
context: context,
);
}
Utils.hideLoading(context); Utils.hideLoading(context);
return status; return status;
@ -93,11 +104,40 @@ class _ChatViewState extends State<ChatView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget? appBarHeadlines;
final requestVM = context.read<RequestsVM>();
if (chatTypeEnum == ChatTypeEnum.requestOffer &&
requestVM.currentSelectedRequest != null &&
(requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.shipping || requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.delivery)) {
appBarHeadlines = Container(
width: double.infinity,
color: MyColors.darkIconColor,
padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
"Your Delivery / Shipping Status is: ".toText(
fontSize: 12,
color: Colors.white,
decorationColor: MyColors.white,
),
Utils.getNameByShippingRequestStatusEnum(requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated).toText(
fontSize: 16,
color: Colors.white,
),
],
),
);
}
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.chat.tr()), appBar: CustomAppBar(
title: LocaleKeys.chat.tr(),
),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) { body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
List<ChatMessageModel> chatMessages = []; List<ChatMessageModel> chatMessages = [];
if (chatTypeEnum == ChatTypeEnum.ads) { if (chatTypeEnum == ChatTypeEnum.general) {
chatMessages = chatVM.currentMessagesForGeneralChat;
} else if (chatTypeEnum == ChatTypeEnum.ads) {
chatMessages = chatVM.currentMessagesForAds; chatMessages = chatVM.currentMessagesForAds;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) { } else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
if (AppState().currentAppType == AppType.customer && chatVM.serviceProviderOffersList.isNotEmpty) { if (AppState().currentAppType == AppType.customer && chatVM.serviceProviderOffersList.isNotEmpty) {
@ -108,16 +148,24 @@ class _ChatViewState extends State<ChatView> {
} }
return Column( return Column(
children: [ children: [
if (appBarHeadlines != null) ...[
appBarHeadlines,
5.height,
],
Expanded( Expanded(
child: chatMessages.isEmpty child: chatMessages.isEmpty
? Center(child: LocaleKeys.noRequestsShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor)) ? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22)
: ListView.separated( : ListView.separated(
controller: chatVM.scrollController, controller: chatVM.scrollController,
itemCount: chatMessages.length, itemCount: chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height, separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatMessages[index]; ChatMessageModel chatMessageModel = chatMessages[index];
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel, requestStatusEnum: requestVM.currentSelectedRequest!.requestStatus); return ChatMessageCustomWidget(
chatMessageModel: chatMessageModel,
requestStatusEnum: requestVM.currentSelectedRequest?.requestStatus,
chatTypeEnum: chatTypeEnum,
);
}, },
).horPaddingMain(), ).horPaddingMain(),
), ),
@ -190,7 +238,7 @@ class _ChatViewState extends State<ChatView> {
onAddFilePressed: () => chatVM.pickMultipleImages(), onAddFilePressed: () => chatVM.pickMultipleImages(),
), ),
), ),
] else ...[ ] else if (chatTypeEnum == ChatTypeEnum.requestOffer) ...[
Expanded( Expanded(
flex: 1, flex: 1,
child: const Icon( child: const Icon(
@ -199,6 +247,8 @@ class _ChatViewState extends State<ChatView> {
size: 30, size: 30,
).onPress(() => chatVM.pickMultipleImages()), ).onPress(() => chatVM.pickMultipleImages()),
), ),
],
if (chatVM.pickedImagesForMessage.isEmpty) ...[
Expanded( Expanded(
flex: 8, flex: 8,
child: TxtField( child: TxtField(

@ -0,0 +1,113 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.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/requests_models/provider_offers_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/utils/utils.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:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class GeneralChatListPage extends StatelessWidget {
final OfferListPageArguments generalChatListPageArguments;
const GeneralChatListPage({super.key, required this.generalChatListPageArguments});
@override
Widget build(BuildContext context) {
final List<ServiceProvidersOffers> serviceProviderOffers = generalChatListPageArguments.serviceProviderOffers;
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.offers.tr()),
body: serviceProviderOffers.isEmpty
? Center(child: LocaleKeys.noOffersShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: serviceProviderOffers.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
ServiceProvidersOffers offersModel = serviceProviderOffers[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(text: "Offer ${Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)}", chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(offersModel.name ?? "").toText(fontSize: 16, isBold: true),
Center(
child: "${offersModel.offerCount}".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: [
"${offersModel.companyName}".toText(color: MyColors.lightTextColor, fontSize: 14),
if (offersModel.createdOn != null && offersModel.createdOn!.isNotEmpty) ...[
" | ${DateTime.parse(offersModel.createdOn!).getTimeAgo()}".toText(color: MyColors.lightTextColor, fontSize: 14),
],
// " | 1 hour ago".toText(
// color: MyColors.lightTextColor,
// fontSize: 12,
// ),
],
),
const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18),
],
),
],
).onPress(() async {
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.providerUserId}",
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
requestId: generalChatListPageArguments.requestId,
providerIndex: index,
requestIndex: -1, // This will be only send in case of provider
);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
final chatVM = context.read<ChatVM>();
await chatVM
.getRequestsChatMessagesForCustomer(
context: context,
providerId: offersModel.providerId ?? 0,
requestOfferId: 0,
requestId: generalChatListPageArguments.requestId ?? 0,
providerOfferIndex: index,
)
.whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
);
}
}

@ -9,6 +9,7 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.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/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart';

@ -1,9 +1,8 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.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/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
@ -11,6 +10,7 @@ import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; 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/utils/utils.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart'; import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart';
@ -24,9 +24,10 @@ import 'package:easy_localization/easy_localization.dart' as lcl;
class ChatMessageCustomWidget extends StatefulWidget { class ChatMessageCustomWidget extends StatefulWidget {
final ChatMessageModel chatMessageModel; final ChatMessageModel chatMessageModel;
final RequestStatusEnum requestStatusEnum; final RequestStatusEnum? requestStatusEnum;
final ChatTypeEnum chatTypeEnum;
const ChatMessageCustomWidget({super.key, required this.chatMessageModel, required this.requestStatusEnum}); const ChatMessageCustomWidget({super.key, required this.chatMessageModel, required this.requestStatusEnum, required this.chatTypeEnum});
@override @override
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState(); State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
@ -424,12 +425,13 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
); );
} }
Widget buildImageGridWidget( Widget buildImageGridWidget({
{required List<MessageImageModel> messagesImages, required List<MessageImageModel> messagesImages,
double gridItemSize = 50.0, // Default fixed size for each grid item double gridItemSize = 50.0,
double spacing = 8.0, double spacing = 8.0,
double borderWidth = 1, double borderWidth = 1,
Color borderColor = MyColors.textColor}) { Color borderColor = MyColors.textColor,
}) {
int imageCount = messagesImages.length; int imageCount = messagesImages.length;
if (imageCount == 1) { if (imageCount == 1) {
return Container( return Container(
@ -447,7 +449,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
) )
: messagesImages[0].imagePath.buildFileImage(fit: BoxFit.cover), : messagesImages[0].imagePath.buildFileImage(fit: BoxFit.cover),
), ),
); ).onPress(() {
navigateWithName(context, AppRoutes.mediaViewerScreen, arguments: messagesImages);
});
} }
return SizedBox( return SizedBox(
// height: (gridItemSize * 2) + (spacing * 2), // Fixed height for 2 rows including spacing // height: (gridItemSize * 2) + (spacing * 2), // Fixed height for 2 rows including spacing
@ -468,7 +472,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return Stack( return Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
(messagesImages[0].isFromNetwork ?? false) (messagesImages[index].isFromNetwork ?? false)
? messagesImages[index].imageUrl.buildNetworkImage( ? messagesImages[index].imageUrl.buildNetworkImage(
fit: BoxFit.cover, fit: BoxFit.cover,
width: gridItemSize, width: gridItemSize,
@ -490,7 +494,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
), ),
), ),
], ],
); ).onPress(() {
navigateWithName(context, AppRoutes.mediaViewerScreen, arguments: messagesImages);
});
} else { } else {
return Container( return Container(
width: gridItemSize, width: gridItemSize,
@ -507,7 +513,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
height: gridItemSize, height: gridItemSize,
), ),
), ),
); ).onPress(() {
navigateWithName(context, AppRoutes.mediaViewerScreen, arguments: messagesImages);
});
} }
}, },
), ),
@ -534,7 +542,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
children: [ children: [
buildFreeTextDetailsInMessage(), buildFreeTextDetailsInMessage(),
10.height, 10.height,
buildOfferDetailsInChatMessage(requestStatusEnum: widget.requestStatusEnum, chatMessageModel: widget.chatMessageModel, context: context), buildOfferDetailsInChatMessage(requestStatusEnum: widget.requestStatusEnum!, chatMessageModel: widget.chatMessageModel, context: context),
], ],
); );
break; break;

@ -125,10 +125,19 @@ class AdsFragment extends StatelessWidget {
Expanded( Expanded(
child: RefreshIndicator( child: RefreshIndicator(
onRefresh: () async { onRefresh: () async {
await adVM.getExploreAds(); if (adVM.isExploreAdsTapped) {
await adVM.getMyAds(); CreatedByRoleEnum createdByRoleEnum = adVM.exploreAdsFilterOptions.firstWhere((element) => element.isSelected).id.toCreatedByRoleEnum();
adVM.applyFilterOnExploreAds(createdByRoleFilter: createdByRoleEnum);
} else {
AdPostStatus adPostStatusEnum = adVM.myAdsFilterOptions.firstWhere((element) => element.isSelected).id.toAdPostEnum();
adVM.applyFilterOnMyAds(adPostStatusEnum: adPostStatusEnum);
}
}, },
child: AdsListWidget(isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM)), child: adVM.state == ViewState.busy
? const Center(
child: CircularProgressIndicator(),
)
: AdsListWidget(isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM)),
), ),
) )
], ],

@ -110,7 +110,7 @@ class MyRequestsFragment extends StatelessWidget {
8.height, 8.height,
Expanded( Expanded(
child: RefreshIndicator( child: RefreshIndicator(
onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true), onRefresh: () async => await requestsVM.getRequestsBasedOnFilters(),
child: requestsVM.state == ViewState.busy child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty : requestsVM.myFilteredRequests.isEmpty

@ -8,6 +8,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/user_view_model.dart'; import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart'; import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -79,7 +80,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
color: Colors.white, color: Colors.white,
child: ListView( child: ListView(
children: [ children: [
20.height, 60.height,
"${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName ?? ""}".toText(fontSize: 20).paddingOnly(left: 25), "${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName ?? ""}".toText(fontSize: 20).paddingOnly(left: 25),
Column( Column(
children: [ children: [
@ -87,6 +88,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
titleText: LocaleKeys.country.tr(), titleText: LocaleKeys.country.tr(),
subtitleText: "Saudi Arabia", subtitleText: "Saudi Arabia",
needBorderBelow: true, needBorderBelow: true,
needEditButton: false,
onTap: () {}, onTap: () {},
), ),
CustomProfileOptionsTile( CustomProfileOptionsTile(
@ -98,7 +100,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
}, },
), ),
CustomProfileOptionsTile( CustomProfileOptionsTile(
titleText: LocaleKeys.phoneNumber.tr(), titleText: LocaleKeys.phone.tr(),
subtitleText: "${AppState().getUser.data!.userInfo!.email}", subtitleText: "${AppState().getUser.data!.userInfo!.email}",
needBorderBelow: true, needBorderBelow: true,
onTap: () { onTap: () {
@ -121,16 +123,16 @@ class _ProfileScreenState extends State<ProfileScreen> {
], ],
), ),
Positioned( Positioned(
top: MediaQuery.of(context).size.height * 0.25, top: MediaQuery.of(context).size.height * 0.24,
child: Container( child: Container(
height: 90, height: 100,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: ClipOval( child: ClipOval(
child: AppState().getUser.data!.userInfo!.userLocalImage != null child: AppState().getUser.data!.userInfo!.userLocalImage != null
? Image.file( ? Image.file(
AppState().getUser.data!.userInfo!.userLocalImage!, AppState().getUser.data!.userInfo!.userLocalImage!,
width: 90, width: 100,
height: 90, height: 100,
fit: BoxFit.fill, fit: BoxFit.fill,
) )
: CachedNetworkImage( : CachedNetworkImage(
@ -145,11 +147,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
), ),
placeholder: (context, url) => const Center(child: CircularProgressIndicator()), placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) => const Icon(Icons.error), errorWidget: (context, url, error) => const Icon(Icons.error),
width: 90, width: 100,
height: 90, height: 100,
fit: BoxFit.fill, fit: BoxFit.fill,
fadeInCurve: Curves.easeIn, fadeInCurve: Curves.easeIn,
fadeInDuration: Duration(milliseconds: 1000), fadeInDuration: const Duration(milliseconds: 1000),
useOldImageOnUrlChange: false, useOldImageOnUrlChange: false,
), ),
), ),
@ -157,18 +159,32 @@ class _ProfileScreenState extends State<ProfileScreen> {
), ),
Positioned( Positioned(
top: MediaQuery.of(context).size.height * 0.30, top: MediaQuery.of(context).size.height * 0.30,
right: MediaQuery.of(context).size.height * 0.036, right: MediaQuery.of(context).size.height * 0.03,
child: Container( child: Container(
height: 35, height: 40,
width: 35, width: 40,
padding: EdgeInsets.all(8),
decoration: BoxDecoration(color: MyColors.white, shape: BoxShape.circle, border: Border.all(color: MyColors.darkTextColor, width: 0.1)), decoration: BoxDecoration(color: MyColors.white, shape: BoxShape.circle, border: Border.all(color: MyColors.darkTextColor, width: 0.1)),
child: const Icon(Icons.edit_note, color: MyColors.darkIconColor, size: 27).paddingOnly(left: 5), child: MyAssets.icEdit.buildSvg(),
).onPress( ).onPress(
() async { () async {
model.updateUserImage(context); await model.updateUserImage(context).whenComplete(() => setState(() {}));
}, },
), ),
), ),
Positioned(
top: MediaQuery.of(context).size.height * 0.05,
left: MediaQuery.of(context).size.height * 0.03,
child: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 18)
.toContainer(
padding: const EdgeInsets.only(left: 5),
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 40,
)
.onPress(() => pop(context))),
], ],
); );
}), }),

@ -7,7 +7,6 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/widgets_models.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/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart'; import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart'; import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart'; import 'package:mc_common_app/views/location_views/pick_location_page.dart';
@ -121,7 +120,7 @@ class CreateRequestPage extends StatelessWidget {
vehicleOwnerDrop.add(DropValue(element.id.toInt(), element.enumValueStr, "")); vehicleOwnerDrop.add(DropValue(element.id.toInt(), element.enumValueStr, ""));
} }
return DropdownField( return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), (DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleOwnerDrop, list: vehicleOwnerDrop,
dropdownValue: requestsVM.vehicleConditionId.selectedId != -1 ? DropValue(requestsVM.vehicleConditionId.selectedId, requestsVM.vehicleConditionId.selectedOption, "") : null, dropdownValue: requestsVM.vehicleConditionId.selectedId != -1 ? DropValue(requestsVM.vehicleConditionId.selectedId, requestsVM.vehicleConditionId.selectedOption, "") : null,
hint: LocaleKeys.condition.tr(), hint: LocaleKeys.condition.tr(),

@ -10,6 +10,7 @@ import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/chat_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/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -34,7 +35,9 @@ class OfferListPage extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
ServiceProvidersOffers offersModel = serviceProviderOffers[index]; ServiceProvidersOffers offersModel = serviceProviderOffers[index];
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Utils.statusContainerChip(text: "Offer ${Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)}", chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -91,7 +94,7 @@ class OfferListPage extends StatelessWidget {
final chatVM = context.read<ChatVM>(); final chatVM = context.read<ChatVM>();
await chatVM await chatVM
.getUsersChatMessagesForCustomer( .getRequestsChatMessagesForCustomer(
context: context, context: context,
providerId: offersModel.providerId ?? 0, providerId: offersModel.providerId ?? 0,
requestOfferId: 0, requestOfferId: 0,

@ -38,9 +38,9 @@ class RequestDetailPage extends StatelessWidget {
case RequestStatusEnum.inProgress: case RequestStatusEnum.inProgress:
if (requestTypeEnum == RequestsTypeEnum.serviceRequest) { if (requestTypeEnum == RequestsTypeEnum.serviceRequest) {
return buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr()); return Utils.buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr());
} else { } else {
return buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr()); return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr());
} }
case RequestStatusEnum.paid: case RequestStatusEnum.paid:
@ -56,13 +56,13 @@ class RequestDetailPage extends StatelessWidget {
}, },
); );
} else { } else {
return buildStatusContainer(LocaleKeys.awaitingResponseFromProvider.tr()); return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromProvider.tr());
} }
case RequestStatusEnum.shipping: case RequestStatusEnum.shipping:
case RequestStatusEnum.delivery: case RequestStatusEnum.delivery:
if (AppState().currentAppType == AppType.provider) { if (AppState().currentAppType == AppType.provider) {
return buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr(), isForShippingOrDelivery: true); return Utils.buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr());
} else { } else {
return ShowFillButton( return ShowFillButton(
maxWidth: double.infinity, maxWidth: double.infinity,
@ -78,26 +78,10 @@ class RequestDetailPage extends StatelessWidget {
case RequestStatusEnum.cancelled: case RequestStatusEnum.cancelled:
case RequestStatusEnum.expired: case RequestStatusEnum.expired:
case RequestStatusEnum.pending: case RequestStatusEnum.pending:
return buildStatusContainer(statusText); return Utils.buildStatusContainer(statusText);
} }
} }
Widget buildStatusContainer(String text, {bool isForShippingOrDelivery = true}) {
return Center(
child: text.toText(
color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor,
fontSize: isForShippingOrDelivery ? 14 : 16,
// isItalic: true,
),
).toContainer(
marginAll: 12,
paddingAll: 12,
borderRadius: 8,
width: double.infinity,
backgroundColor: isForShippingOrDelivery ? MyColors.grey98Color.withOpacity(0.1) : MyColors.adPendingStatusColor.withOpacity(0.16),
);
}
Future<void> onViewChatTapped(BuildContext context) async { Future<void> onViewChatTapped(BuildContext context) async {
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest( ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer, chatTypeEnum: ChatTypeEnum.requestOffer,
@ -115,7 +99,7 @@ class RequestDetailPage extends StatelessWidget {
); );
final chatVM = context.read<ChatVM>(); final chatVM = context.read<ChatVM>();
await chatVM await chatVM
.getUsersChatMessagesForProvider( .getRequestsChatMessagesForProvider(
customerId: requestDetailPageArguments.requestModel.customerId, customerId: requestDetailPageArguments.requestModel.customerId,
context: context, context: context,
requestOfferId: 0, requestOfferId: 0,

@ -43,7 +43,7 @@ class RequestItem extends StatelessWidget {
children: [ children: [
Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)), Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)),
6.height, 6.height,
"${request.brand} ${request.model}".toText(fontSize: 16, letterSpacing: -0.64), "${request.brand} ${request.model} | ${request.id}".toText(fontSize: 16, letterSpacing: -0.64),
showItem("${LocaleKeys.model.tr()}:", "${request.year}"), showItem("${LocaleKeys.model.tr()}:", "${request.year}"),
if (request.customerName.isNotEmpty) ...[ if (request.customerName.isNotEmpty) ...[
showItem("${LocaleKeys.customerName.tr()}:", request.customerName), showItem("${LocaleKeys.customerName.tr()}:", request.customerName),

@ -1,7 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
@ -9,14 +7,15 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/document.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/document.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; 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/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/service_view_model.dart'; import 'package:mc_common_app/view_models/service_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart'; import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/app_bar.dart';
@ -40,9 +39,9 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
scheduleMicrotask(() { scheduleMicrotask(() async {
// branchVM = Provider.of<ServiceVM>(context, listen: false); final serviceVm = context.read<ServiceVM>();
context.read<ServiceVM>().getServiceProviderDocument(AppState().getUser.data!.userInfo!.providerId ?? 0); await serviceVm.getServiceProviderDocument(AppState().getUser.data!.userInfo!.providerId ?? 0);
}); });
} }
@ -53,51 +52,55 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
title: LocaleKeys.defineLicences.tr(), title: LocaleKeys.defineLicences.tr(),
isRemoveBackButton: false, isRemoveBackButton: false,
), ),
body: Consumer<ServiceVM>(builder: (_, model, __) { body: Consumer<ServiceVM>(builder: (_, serviceVM, __) {
if (serviceVM.state == ViewState.busy) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(child: buildContent(serviceVM)),
child: Padding(
padding: const EdgeInsets.all(0.0),
child: Column(
children: [
showWidget(model),
],
),
),
),
), ),
if (!serviceVM.isAllDocsApproved) ...[
Padding( Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: ShowFillButton( child: ShowFillButton(
title: LocaleKeys.continu.tr(), title: LocaleKeys.continu.tr(),
maxWidth: double.infinity, maxWidth: double.infinity,
onPressed: () { onPressed: () async {
bool status = false;
if (AppState().getUser.data!.userInfo!.roleId == 5) { if (AppState().getUser.data!.userInfo!.roleId == 5) {
if (validation(model)) { if (validateDocuments(serviceVM)) {
updateDocument(model); status = await updateDocument(serviceVM);
} else { } else {
Utils.showToast(LocaleKeys.allDocumentMandatoryDealershipProvider.tr()); Utils.showToast(LocaleKeys.allDocumentMandatoryDealershipProvider.tr());
return;
} }
} else { } else {
updateDocument(model); status = await updateDocument(serviceVM);
} }
Future.delayed(const Duration(seconds: 1), () { Future.delayed(const Duration(seconds: 1), () {
Navigator.of(context).pop(); if (status) {
pop(context);
}
}); });
}, },
), ),
), ),
], ],
],
); );
}), }),
); );
} }
validation(ServiceVM model) { validateDocuments(ServiceVM model) {
bool valid = true; bool valid = true;
for (var element in model.document!.data!) { for (var element in model.document!.data!) {
log("documentUrl: ${element.documentUrl}");
if (element.documentUrl == null) { if (element.documentUrl == null) {
valid = false; valid = false;
} }
@ -105,126 +108,101 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
return valid; return valid;
} }
updateDocument(ServiceVM model) async { Future<bool> updateDocument(ServiceVM model) async {
try {
Utils.showLoading(context); Utils.showLoading(context);
GenericRespModel res = await model.updateDocument(model.document!.data); GenericRespModel res = await model.updateDocument(model.document!.data);
Utils.hideLoading(context); Utils.hideLoading(context);
if (res.messageStatus == 1) { if (res.messageStatus == 1) {
Utils.showToast(LocaleKeys.documentsUploadedSuccessfully.tr()); Utils.showToast(LocaleKeys.documentsUploadedSuccessfully.tr());
Navigator.of(context).pop(); Navigator.of(context).pop();
return true;
} else { } else {
Utils.showToast(res.message ?? ""); Utils.showToast(res.message ?? "");
return false;
}
} catch (e, s) {
return false;
} }
} }
Widget showWidget(ServiceVM model) { Widget buildContent(ServiceVM serviceVM) {
if (model.state == ViewState.idle) { return serviceVM.document!.data!.isEmpty
return model.document!.data!.isEmpty
? Text(LocaleKeys.somethingWrong.tr()) ? Text(LocaleKeys.somethingWrong.tr())
: ListView.separated( : ListView.separated(
separatorBuilder: (context, index) {
return 20.height;
},
itemCount: serviceVM.document!.data!.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemBuilder: (context, index) { itemBuilder: (context, index) {
DocumentData? document = model.document?.data![index]; DocumentData? document = serviceVM.document?.data![index];
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
10.height, 10.height,
(document!.documentName! ?? "").toText(fontSize: 16, letterSpacing: -0.56, fontWeight: MyFonts.SemiBold), Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(document!.documentName!).toText(fontSize: 16, letterSpacing: -0.56, fontWeight: MyFonts.SemiBold),
if (document.statusText != null && document.statusText!.isNotEmpty) ...[
10.width,
Utils.statusContainerChip(text: document.statusText!.replaceFirst('OrActive', ''), chipColor: getColorByStatus(document.status ?? 1)),
],
],
),
if (document.status != 1 && document.status != 3) ...[
Padding( Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 4, bottom: 8), padding: const EdgeInsets.only(top: 4, bottom: 8),
child: LocaleKeys.enter_licence_detail.tr().toText(fontSize: 14, color: MyColors.lightTextColor, textAlign: TextAlign.center), child: LocaleKeys.enter_licence_detail.tr().toText(fontSize: 14, color: MyColors.lightTextColor),
), ),
TxtField( TxtField(
hint: LocaleKeys.description.tr(), hint: LocaleKeys.description.tr(),
maxLines: 3, maxLines: 3,
isBackgroundEnabled: true, isBackgroundEnabled: true,
), ),
],
10.height, 10.height,
if (isNeedToShow(model: model, document: document)) ...[ if (isNeedToShow(model: serviceVM, document: document)) ...[
PickedFilesContainer( PickedFilesContainer(
// isReview: document.status == 3 ? true : false, isReview: document.status == 4,
pickedFiles: isLocalOrNetworkFiles(model: model, document: document), allowAdButton: false,
onCrossPressedPrimary: chkIsLocalOrNetwork(document: document) pickedFiles: isLocalOrNetworkFiles(model: serviceVM, document: document),
? model.removeNetworkImag onCrossPressedPrimary: isNetworkImage(document: document)
? serviceVM.removeNetworkImage
: document.documentId == 1 : document.documentId == 1
? model.commerceRemove ? serviceVM.commerceRemove
: document.documentId == 2 : document.documentId == 2
? model.commercialRemove ? serviceVM.commercialRemove
: model.vatRemove, : serviceVM.vatRemove,
isPdf: model.document!.data![index].fileExt == "pdf", isPdf: serviceVM.document!.data![index].fileExt == "pdf",
isFromNetwork: document.isLocalFile! ? false : true, isFromNetwork: !(document.isLocalFile ?? false),
onAddFilePressed: () { onAddFilePressed: () {
model.pickPdfReceiptFile(context, document.documentId!, index); serviceVM.pickPdfReceiptFile(context, document.documentId!, index);
}, },
), ),
if (document.comment != null && document.comment.isNotEmpty && document.status == 4) ...[buildStatusContainer(document: document)] buildCommentContainer(document: document),
] else ] else ...[
...[
10.height, 10.height,
InkWell( DottedRectContainer(
onTap: () async { onTap: () => serviceVM.pickPdfReceiptFile(context, document.documentId!, index) ?? "",
model.pickPdfReceiptFile(context, document.documentId!, index) ?? ""; text: LocaleKeys.attachImage.tr(),
}, icon: MyAssets.attachmentIcon.buildSvg(),
child: Container(
width: double.infinity,
height: 45,
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(color: MyColors.greyACColor, width: 2),
borderRadius: const BorderRadius.all(Radius.circular(0)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.attach_file,
size: 18,
color: MyColors.darkPrimaryColor,
),
8.width,
Text(
LocaleKeys.attachFile.tr(),
style: const TextStyle(
color: MyColors.darkPrimaryColor,
),
),
const Icon(
Icons.attach_file,
size: 18,
color: Colors.transparent,
),
],
),
),
), ),
], ],
], ],
); );
}, },
separatorBuilder: (context, index) {
return 20.height;
},
itemCount: model.document!.data!.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: 20),
); );
} else {
return Column(
children: [
20.height,
const Center(
child: CircularProgressIndicator(),
),
],
);
}
} }
List<ImageModel> isLocalOrNetworkFiles({required ServiceVM model, required DocumentData document}) { List<ImageModel> isLocalOrNetworkFiles({required ServiceVM model, required DocumentData document}) {
bool isNetworkImage = false; bool isNetworkImage = false;
if (!document.isLocalFile!) { if (!document.isLocalFile!) {
isNetworkImage = document.documentUrl != null && document.documentUrl.isNotEmpty ? true : false; isNetworkImage = document.documentUrl != null && document.documentUrl!.isNotEmpty ? true : false;
} }
if (isNetworkImage) { if (isNetworkImage) {
return [ImageModel(id: document.id, isFromNetwork: isNetworkImage, filePath: document.documentUrl)]; return [ImageModel(id: document.id, isFromNetwork: isNetworkImage, filePath: document.documentUrl)];
@ -239,7 +217,7 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
bool isNeedToShow({required ServiceVM model, required DocumentData document}) { bool isNeedToShow({required ServiceVM model, required DocumentData document}) {
bool allow = false; bool allow = false;
bool isNetworkImage = document.documentUrl != null && document.documentUrl.isNotEmpty ? true : false; bool isNetworkImage = document.documentUrl != null && document.documentUrl!.isNotEmpty && !(document.isLocalFile ?? true);
if (isNetworkImage) { if (isNetworkImage) {
allow = true; allow = true;
} else { } else {
@ -257,7 +235,7 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
} }
dynamic checkOnCrossPress({required ServiceVM model, required DocumentData document}) async { dynamic checkOnCrossPress({required ServiceVM model, required DocumentData document}) async {
bool isNetworkImage = document.documentUrl != null && document.documentUrl.isNotEmpty ? true : false; bool isNetworkImage = document.documentUrl != null && document.documentUrl!.isNotEmpty ? true : false;
if (isNetworkImage) { if (isNetworkImage) {
return document.documentUrl; return document.documentUrl;
} else { } else {
@ -273,27 +251,47 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
} }
} }
bool chkIsLocalOrNetwork({required DocumentData document}) { bool isNetworkImage({required DocumentData document}) {
bool isNetworkImage = false; bool isNetworkImage = false;
if (!document.isLocalFile!) { if (!document.isLocalFile!) {
isNetworkImage = document.documentUrl != null && document.documentUrl.isNotEmpty ? true : false; isNetworkImage = document.documentUrl != null && document.documentUrl!.isNotEmpty ? true : false;
} }
return isNetworkImage; return isNetworkImage;
} }
Widget buildStatusContainer({required DocumentData document}) { Widget buildCommentContainer({required DocumentData document}) {
return Center( String comment = "";
child: document.comment.toString().toText( if (document.status == 4 && document.comment != null) {
color: MyColors.adCancelledStatusColor, comment = document.comment ?? "";
fontSize: 14, }
// isItalic: true,
), if (comment.isEmpty) {
).toContainer( return const SizedBox();
marginAll: 10, }
paddingAll: 10, return Center(child: comment.toString().toText(color: MyColors.adCancelledStatusColor, fontSize: 14)).toContainer(
borderRadius: 8, borderRadius: 8,
margin: const EdgeInsets.only(top: 10),
width: double.infinity, width: double.infinity,
backgroundColor: MyColors.adCancelledStatusColor.withOpacity(0.16), backgroundColor: MyColors.adCancelledStatusColor.withOpacity(0.16),
); );
} }
Color getColorByStatus(int docStatus) {
switch (docStatus) {
case 1:
return MyColors.adPendingStatusColor;
case 2:
return MyColors.adActiveStatusColor;
case 3:
return MyColors.greenColor;
case 4:
return MyColors.adCancelledStatusColor;
default:
return MyColors.adPendingStatusColor;
}
}
} }

@ -3,7 +3,9 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -28,79 +30,51 @@ class SettingOptionsHelp extends StatelessWidget {
Column( Column(
children: [ children: [
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.info_rounded, size: 20), leadingWidget: const Icon(
Icons.info_rounded,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.faqs.tr(), titleText: LocaleKeys.faqs.tr(),
needBorderBelow: true, needBorderBelow: true,
onTap: () {}, onTap: () => navigateWithName(context, AppRoutes.settingOptionsFaqs),
), ),
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.mail, size: 20), leadingWidget: const Icon(
Icons.mail,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.contactUs.tr(), titleText: LocaleKeys.contactUs.tr(),
needBorderBelow: true, needBorderBelow: true,
onTap: () => navigateWithName( onTap: () => navigateWithName(context, AppRoutes.settingOptionsContactUs),
context, AppRoutes.settingOptionsFaqs),
), ),
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.lock, size: 20), leadingWidget: const Icon(
Icons.lock,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.termPrivacy.tr(), titleText: LocaleKeys.termPrivacy.tr(),
onTap: () => needBorderBelow: true,
navigateWithName(context, AppRoutes.profileView), onTap: () {},
), ),
], CustomSettingOptionsTile(
).toContainer( leadingWidget: const Icon(
width: double.infinity, Icons.info_rounded,
isShadowEnabled: true, size: 20,
paddingAll: 10, color: MyColors.greyColor,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0),
borderRadius: 0),
],
), ),
titleText: LocaleKeys.appInfo.tr(),
onTap: () => navigateWithName(context, AppRoutes.settingOptionsAppInfo),
), ),
], ],
), ).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(21, 24, 21, 0), borderRadius: 0),
);
}
}
class CustomSettingOptionsTile extends StatelessWidget {
final Widget leadingWidget;
final String titleText;
final bool needBorderBelow;
final bool isForLanguage;
final Function() onTap;
const CustomSettingOptionsTile(
{super.key,
required this.leadingWidget,
required this.onTap,
required this.titleText,
this.needBorderBelow = false,
this.isForLanguage = false});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
leadingWidget,
12.width,
titleText.toText(fontSize: 16),
], ],
), ),
isForLanguage ),
? const Icon(Icons.language, size: 18)
: const Icon(Icons.arrow_forward, size: 18)
],
).onPress(onTap),
5.height,
if (needBorderBelow) ...[
const Divider(thickness: 1),
],
], ],
),
); );
} }
} }

@ -0,0 +1,117 @@
import 'dart:async';
import 'package:flutter/cupertino.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.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/view_models/setting_options_view_model.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.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 SettingOptionsAppInfo extends StatefulWidget {
const SettingOptionsAppInfo({super.key});
@override
State<SettingOptionsAppInfo> createState() => _SettingOptionsAppInfoState();
}
class _SettingOptionsAppInfoState extends State<SettingOptionsAppInfo> {
late SettingOptionsVM settingsOptionsVM;
@override
void initState() {
settingsOptionsVM = context.read<SettingOptionsVM>();
scheduleMicrotask(() async {
await settingsOptionsVM.getAppInfoList();
});
super.initState();
}
Widget showData(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(
fontSize: 13,
color: MyColors.darkTextColor,
),
if (title.isNotEmpty) 5.width,
Flexible(
child: value.toText(
fontSize: 13,
color: MyColors.lightTextColor,
),
)
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.appInfo.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Consumer(
builder: (BuildContext context, SettingOptionsVM settingsOptionsVM, Widget? child) {
return Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Column(
children: [
16.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await settingsOptionsVM.getAllFaqs(),
child: (settingsOptionsVM.state == ViewState.busy)
? const Center(child: CircularProgressIndicator())
: settingsOptionsVM.appInfoList.isEmpty
? Padding(
padding: const EdgeInsets.all(21),
child: Center(child: LocaleKeys.somethingWrong.tr().toText(textAlign: TextAlign.center, fontSize: 16, color: MyColors.lightTextColor)),
)
: ListView.separated(
itemCount: settingsOptionsVM.appInfoList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
AppInfoModel appInfoModel = settingsOptionsVM.appInfoList[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(appInfoModel.header ?? "").toString().toText(fontSize: 16),
5.height,
(appInfoModel.content ?? "").toString().toText(fontSize: 14, color: MyColors.lightTextColor),
if (appInfoModel.appInfoImages != null && appInfoModel.appInfoImages!.isNotEmpty) ...[
PickedFilesContainer(
pickedFiles: appInfoModel.appInfoImages ?? [],
isReview: true,
onAddFilePressed: () {},
),
]
],
).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
)),
],
),
);
},
));
}
}

@ -0,0 +1,123 @@
import 'dart:async';
import 'package:flutter/cupertino.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.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/view_models/setting_options_view_model.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.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 SettingOptionsContactUs extends StatefulWidget {
const SettingOptionsContactUs({super.key});
@override
State<SettingOptionsContactUs> createState() => _SettingOptionsContactUsState();
}
class _SettingOptionsContactUsState extends State<SettingOptionsContactUs> {
late SettingOptionsVM settingsOptionsVM;
@override
void initState() {
settingsOptionsVM = context.read<SettingOptionsVM>();
scheduleMicrotask(() async {
await settingsOptionsVM.getAllContactInfosList();
});
super.initState();
}
Widget showData(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(
fontSize: 13,
color: MyColors.darkTextColor,
),
if (title.isNotEmpty) 5.width,
Flexible(
child: value.toText(
fontSize: 13,
color: MyColors.lightTextColor,
),
)
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.contactUs.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Consumer(
builder: (BuildContext context, SettingOptionsVM settingsOptionsVM, Widget? child) {
return Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Column(
children: [
16.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await settingsOptionsVM.getAllFaqs(),
child: (settingsOptionsVM.state == ViewState.busy)
? const Center(child: CircularProgressIndicator())
: settingsOptionsVM.contactInfosList.isEmpty
? Padding(
padding: const EdgeInsets.all(21),
child: Center(child: LocaleKeys.somethingWrong.tr().toText(textAlign: TextAlign.center, fontSize: 16, color: MyColors.lightTextColor)),
)
: ListView.separated(
itemCount: settingsOptionsVM.contactInfosList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
ContactInfoModel contactInfoModel = settingsOptionsVM.contactInfosList[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
contactInfoModel.companyName.toString().toText(fontSize: 16),
5.height,
LocaleKeys.openMapLocation.tr().toText(isUnderLine: true, color: MyColors.darkPrimaryColor, fontSize: 10).onPress(() {}),
showData("${LocaleKeys.phoneNumber.tr()}:", "${contactInfoModel.phoneNo}"),
showData("${LocaleKeys.email.tr()}:", "${contactInfoModel.email}"),
if (contactInfoModel.address != null && contactInfoModel.address!.isNotEmpty) ...[
showData("${LocaleKeys.address.tr()}:", ''),
"${contactInfoModel.address}".toText(height: 1.5, fontSize: 13, color: MyColors.lightTextColor),
],
if (contactInfoModel.contactInfoImages != null && contactInfoModel.contactInfoImages!.isNotEmpty) ...[
PickedFilesContainer(
pickedFiles: contactInfoModel.contactInfoImages ?? [],
isReview: true,
onAddFilePressed: () {},
),
]
],
).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
)),
],
),
);
},
));
}
}

@ -1,61 +1,104 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart'; import 'package:mc_common_app/models/setting_utils_models/faqs_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/setting_options_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
class SettingOptionsFAQs extends StatelessWidget { class SettingOptionsFAQs extends StatefulWidget {
const SettingOptionsFAQs({super.key}); const SettingOptionsFAQs({super.key});
@override
State<SettingOptionsFAQs> createState() => _SettingOptionsFAQsState();
}
class _SettingOptionsFAQsState extends State<SettingOptionsFAQs> {
late SettingOptionsVM settingsOptionsVM;
@override
void initState() {
settingsOptionsVM = context.read<SettingOptionsVM>();
scheduleMicrotask(() async {
await settingsOptionsVM.getAllFaqs();
});
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.more.tr(), title: LocaleKeys.faqs.tr(),
isRemoveBackButton: false, isRemoveBackButton: false,
isDrawerEnabled: false, isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
), ),
body: Column( body: Consumer(
builder: (BuildContext context, SettingOptionsVM settingsOptionsVM, Widget? child) {
return Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Column(
children: [ children: [
16.height,
Expanded( Expanded(
child: ListView( child: RefreshIndicator(
onRefresh: () async => await settingsOptionsVM.getAllFaqs(),
child: (settingsOptionsVM.state == ViewState.busy)
? const Center(child: CircularProgressIndicator())
: settingsOptionsVM.faqsList.isEmpty
? Padding(
padding: const EdgeInsets.all(21),
child: Center(child: LocaleKeys.noFAQsToShow.tr().toText(textAlign: TextAlign.center, fontSize: 16, color: MyColors.lightTextColor)),
)
: ListView.separated(
itemCount: settingsOptionsVM.faqsList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
FAQsModel faqModel = settingsOptionsVM.faqsList[index];
return ExpansionTile(
tilePadding: EdgeInsets.zero,
shape: const Border(),
title: (faqModel.question ?? "").toText(fontSize: 16).paddingOnly(left: 8, right: 8),
onExpansionChanged: (value) {
setState(() {
settingsOptionsVM.faqsList[index].isCollapsed = value;
});
},
backgroundColor: Colors.transparent,
collapsedBackgroundColor: Colors.transparent,
initiallyExpanded: settingsOptionsVM.faqsList[index].isCollapsed ?? false,
trailing: (settingsOptionsVM.faqsList[index].isCollapsed ?? false) ? const Icon(Icons.keyboard_arrow_up) : const Icon(Icons.keyboard_arrow_down),
subtitle: ("Channel: ${faqModel.channel.toString()}").toText(color: MyColors.lightTextColor).paddingOnly(left: 8, right: 8),
children: [ children: [
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CustomSettingOptionsTile( 5.height,
leadingWidget: const Icon(Icons.info, size: 20), (faqModel.answer ?? "").toText(color: MyColors.lightTextColor, fontSize: 14, fontWeight: MyFonts.Medium),
titleText: LocaleKeys.faqs.tr(), 10.height,
needBorderBelow: true,
onTap: () {}),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.mail, size: 20),
titleText: LocaleKeys.contactUs.tr(),
needBorderBelow: true,
onTap: () {}),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.termPrivacy.tr(),
onTap: () {}),
], ],
).toContainer( ).paddingOnly(left: 8, right: 8)
width: double.infinity,
isShadowEnabled: true,
paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0),
borderRadius: 0),
], ],
).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 12.height,
), ),
), )),
Row(
children: [
"Version: 1.0.0".toText(fontSize: 14),
],
).paddingAll(21),
], ],
), ),
); );
},
));
} }
} }

@ -1,21 +1,76 @@
import 'package:flutter/material.dart'; 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/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
class SettingOptionsInviteFriends extends StatelessWidget { class SettingOptionsInviteFriends extends StatelessWidget {
const SettingOptionsInviteFriends({super.key}); const SettingOptionsInviteFriends({super.key});
buildInviteFriendsBottomSheet(BuildContext context) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
20.height,
CustomSettingOptionsTile(
leadingWidget: MyAssets.whatsAppIcon.buildSvg(
height: 20,
width: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByWhatsApp.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () {},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.sms_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsBySMS.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () {},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.email_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByEmail.tr(),
needBorderBelow: false,
showTrailingArrow: false,
onTap: () {},
),
30.height,
],
),
title: const SizedBox());
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.more.tr(), title: LocaleKeys.settings.tr(),
isRemoveBackButton: false, isRemoveBackButton: false,
isDrawerEnabled: false, isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
@ -28,79 +83,39 @@ class SettingOptionsInviteFriends extends StatelessWidget {
Column( Column(
children: [ children: [
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20), leadingWidget: const Icon(Icons.group, size: 20),
titleText: LocaleKeys.inviteFriends.tr(), titleText: LocaleKeys.inviteFriends.tr(),
needBorderBelow: true, needBorderBelow: true,
onTap: () {}, onTap: () {
return buildInviteFriendsBottomSheet(context);
},
), ),
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.help, size: 20), leadingWidget: const Icon(Icons.question_mark_outlined, size: 20),
titleText: LocaleKeys.help.tr(), titleText: LocaleKeys.help.tr(),
needBorderBelow: true, needBorderBelow: true,
onTap: () => navigateWithName( onTap: () => navigateWithName(context, AppRoutes.settingOptionsHelp),
context, AppRoutes.settingOptionsFaqs),
), ),
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20), leadingWidget: const Icon(Icons.person, size: 20),
titleText: LocaleKeys.account.tr(), titleText: LocaleKeys.account.tr(),
onTap: () => needBorderBelow: false,
navigateWithName(context, AppRoutes.profileView), onTap: () {
), navigateWithName(context, AppRoutes.profileView);
}),
], ],
).toContainer( ).toContainer(
width: double.infinity, width: double.infinity,
isShadowEnabled: true, isShadowEnabled: true,
paddingAll: 10, paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), margin: const EdgeInsets.fromLTRB(21, 21, 21, 0),
borderRadius: 0), borderRadius: 0,
],
),
), ),
], ],
), ),
);
}
}
class CustomSettingOptionsTile extends StatelessWidget {
final Widget leadingWidget;
final String titleText;
final bool needBorderBelow;
final bool isForLanguage;
final Function() onTap;
const CustomSettingOptionsTile(
{super.key,
required this.leadingWidget,
required this.onTap,
required this.titleText,
this.needBorderBelow = false,
this.isForLanguage = false});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
leadingWidget,
12.width,
titleText.toText(fontSize: 16),
],
), ),
isForLanguage
? const Icon(Icons.language, size: 18)
: const Icon(Icons.arrow_forward, size: 18)
],
).onPress(onTap),
5.height,
if (needBorderBelow) ...[
const Divider(thickness: 1),
],
], ],
),
); );
} }
} }

@ -1,223 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mc_common_app/classes/app_state.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/generated/locale_keys.g.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/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.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/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class SettingOptionsLanguage extends StatefulWidget {
const SettingOptionsLanguage({super.key});
@override
State<SettingOptionsLanguage> createState() => _SettingOptionsLanguageState();
}
class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.more.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Column(
children: [
// (AppState().currentAppType == AppType.provider)
// ?
Expanded(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.zero,
children: [
Column(
children: [
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.quickreply_outlined, size: 20),
titleText: LocaleKeys.requests.tr(),
needBorderBelow: true,
onTap: () {
context.read<DashboardVmCustomer>().onNavbarTapped(4);
Navigator.pop(context);
}),
if (AppState().currentAppType == AppType.customer) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.favorite, size: 20),
titleText: LocaleKeys.favoriteList.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.favoriteListView),
),
],
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),
needBorderBelow: true,
onTap: () {},
//navigateWithName(context, AppRoutes.settingOptionsInviteFriends),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.question_mark_outlined, size: 20),
titleText: LocaleKeys.help.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsHelp),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20),
titleText: LocaleKeys.account.tr(),
needBorderBelow: false,
onTap: () {
navigateWithName(context, AppRoutes.profileView);
// context.read<DashboardVmCustomer>().onNavbarTapped(4);
// Navigator.pop(context);
}),
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
10.height,
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.translate, size: 20),
titleText: LocaleKeys.language.tr(),
isForLanguage: true,
onTap: () {
context.read<UserVM>().changeLanguage(context);
Future.delayed(Duration(seconds: 1), () {
setState(() {});
});
},
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
10.height,
(AppState().currentAppType == AppType.provider)
? Column(
children: [
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icStar,
color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.mySubscription.tr(),
subTitle: AppState().getproviderSubscription.first.name,
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.mySubscriptionsPage);
},
),
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icGroupStar,
// color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.subscriptions.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.subscriptionsPage);
},
),
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icGroupStar,
// color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.defineLicenses.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: false,
onTap: () {
navigateWithName(context, AppRoutes.providerLicensePage);
},
),
// CustomSettingOptionsTile(
// leadingWidget: SizedBox(
// width: 16,
// height: 16,
// child: SvgPicture.asset(
// MyAssets.providersIcon,
// // color: MyColors.primaryColor,
// ),
// ),
// titleText: "Users",
// subTitle: null,
// isForLanguage: false,
// needBorderBelow: false,
// onTap: () {
// navigateWithName(context, AppRoutes.dealerUser, arguments: AppState().getUser.data!.userInfo!.id.toString());
// },
// )
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0)
: const SizedBox(),
(AppState().currentAppType == AppType.provider) ? 10.height : const SizedBox(),
],
)),
// : Expanded(
// child: ListView(
// children: [
// Column(
// children: [
// CustomSettingOptionsTile(
// leadingWidget: const Icon(Icons.person, size: 20),
// titleText: "My Requests",
// needBorderBelow: true,
// onTap: () {
// context.read<DashboardVmCustomer>().onNavbarTapped(4);
// Navigator.pop(context);
// }),
// CustomSettingOptionsTile(leadingWidget: const Icon(Icons.favorite, size: 20), titleText: "Favorite list", needBorderBelow: true, onTap: () {}),
// CustomSettingOptionsTile(
// leadingWidget: const Icon(Icons.settings, size: 20), titleText: "Settings", onTap: () => navigateWithName(context, AppRoutes.settingOptionsInviteFriends)),
// ],
// ).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
// CustomSettingOptionsTile(leadingWidget: const Icon(Icons.translate, size: 20), titleText: "Language", isForLanguage: true, onTap: () {})
// .toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, marginAll: 21, borderRadius: 0),
// ],
// ),
// ),
(AppState().currentAppType == AppType.provider) ? Text(LocaleKeys.provider.tr()) : Text(LocaleKeys.customer.tr()),
Row(
children: [
Expanded(
child: ShowFillButton(
borderColor: MyColors.redColor,
txtColor: MyColors.redColor,
isFilled: false,
fontSize: 16,
maxHeight: 55,
title: LocaleKeys.logOut.tr(),
onPressed: () {
context.read<UserVM>().logout(context);
},
),
),
],
).paddingAll(0),
],
).paddingAll(21),
);
}
}

@ -0,0 +1,210 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mc_common_app/classes/app_state.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.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/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.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/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class SettingOptionsMore extends StatefulWidget {
const SettingOptionsMore({super.key});
@override
State<SettingOptionsMore> createState() => _SettingOptionsMoreState();
}
class _SettingOptionsMoreState extends State<SettingOptionsMore> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.more.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Column(
children: [
// (AppState().currentAppType == AppType.provider)
// ?
Expanded(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.zero,
children: [
Column(
children: [
if (AppState().currentAppType == AppType.customer) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.favorite, size: 20),
titleText: LocaleKeys.favoriteList.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.favoriteListView),
),
] else ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.local_shipping, size: 20),
titleText: LocaleKeys.shippingManagement.tr(),
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.shippingManagementView);
},
),
],
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),
needBorderBelow: false,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsInviteFriends),
),
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
10.height,
if (!disableThingsForQA) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.translate, size: 20),
titleText: LocaleKeys.language.tr(),
isForLanguage: true,
onTap: () {
context.read<UserVM>().changeLanguage(context);
Future.delayed(const Duration(seconds: 1), () {
setState(() {});
});
},
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
10.height,
],
(AppState().currentAppType == AppType.provider)
? Column(
children: [
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icStar,
color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.mySubscription.tr(),
subTitle: AppState().getproviderSubscription.first.name ?? "",
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.mySubscriptionsPage);
},
),
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icGroupStar,
// color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.subscriptions.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.subscriptionsPage);
},
),
CustomSettingOptionsTile(
leadingWidget: SizedBox(
width: 16,
height: 16,
child: SvgPicture.asset(
MyAssets.icGroupStar,
// color: MyColors.primaryColor,
),
),
titleText: LocaleKeys.defineLicenses.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: false,
onTap: () {
navigateWithName(context, AppRoutes.providerLicensePage);
},
),
// CustomSettingOptionsTile(
// leadingWidget: SizedBox(
// width: 16,
// height: 16,
// child: SvgPicture.asset(
// MyAssets.providersIcon,
// // color: MyColors.primaryColor,
// ),
// ),
// titleText: "Users",
// subTitle: null,
// isForLanguage: false,
// needBorderBelow: false,
// onTap: () {
// navigateWithName(context, AppRoutes.dealerUser, arguments: AppState().getUser.data!.userInfo!.id.toString());
// },
// )
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0)
: const SizedBox(),
(AppState().currentAppType == AppType.provider) ? 10.height : const SizedBox(),
],
)),
// : Expanded(
// child: ListView(
// children: [
// Column(
// children: [
// CustomSettingOptionsTile(
// leadingWidget: const Icon(Icons.person, size: 20),
// titleText: "My Requests",
// needBorderBelow: true,
// onTap: () {
// context.read<BaseVM>().onNavbarTapped(4);
// Navigator.pop(context);
// }),
// CustomSettingOptionsTile(leadingWidget: const Icon(Icons.favorite, size: 20), titleText: "Favorite list", needBorderBelow: true, onTap: () {}),
// CustomSettingOptionsTile(
// leadingWidget: const Icon(Icons.settings, size: 20), titleText: "Settings", onTap: () => navigateWithName(context, AppRoutes.settingOptionsInviteFriends)),
// ],
// ).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
// CustomSettingOptionsTile(leadingWidget: const Icon(Icons.translate, size: 20), titleText: "Language", isForLanguage: true, onTap: () {})
// .toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, marginAll: 21, borderRadius: 0),
// ],
// ),
// ),
Row(
children: [
Expanded(
child: ShowFillButton(
borderColor: MyColors.redColor,
txtColor: MyColors.redColor,
isFilled: false,
fontSize: 16,
maxHeight: 55,
title: LocaleKeys.logOut.tr(),
onPressed: () {
context.read<UserVM>().logout(context);
},
),
),
],
).paddingAll(0),
],
).paddingAll(21),
);
}
}

@ -1,17 +1,18 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:sizer/sizer.dart';
class CustomSettingOptionsTile extends StatelessWidget { class CustomSettingOptionsTile extends StatelessWidget {
final Widget leadingWidget; final Widget leadingWidget;
final String titleText; final String titleText;
final bool needBorderBelow; final bool needBorderBelow;
final bool isForLanguage; final bool isForLanguage;
final bool showTrailingArrow;
final Function() onTap; final Function() onTap;
final String? subTitle; final String? subTitle;
@ -22,6 +23,7 @@ class CustomSettingOptionsTile extends StatelessWidget {
required this.titleText, required this.titleText,
this.needBorderBelow = false, this.needBorderBelow = false,
this.isForLanguage = false, this.isForLanguage = false,
this.showTrailingArrow = true,
this.subTitle, this.subTitle,
}); });
@ -61,7 +63,9 @@ class CustomSettingOptionsTile extends StatelessWidget {
// ) // )
// //
: const Icon(Icons.arrow_forward, size: 18) : showTrailingArrow
? const Icon(Icons.arrow_forward, size: 18)
: const SizedBox()
], ],
).onPress(onTap), ).onPress(onTap),
subTitle != null ? 3.height : 5.height, subTitle != null ? 3.height : 5.height,
@ -76,10 +80,11 @@ class CustomSettingOptionsTile extends StatelessWidget {
class CustomProfileOptionsTile extends StatelessWidget { class CustomProfileOptionsTile extends StatelessWidget {
final String titleText; final String titleText;
final bool needBorderBelow; final bool needBorderBelow;
final bool needEditButton;
final Function() onTap; final Function() onTap;
final String subtitleText; final String subtitleText;
const CustomProfileOptionsTile({super.key, required this.onTap, required this.titleText, required this.subtitleText, this.needBorderBelow = false}); const CustomProfileOptionsTile({super.key, required this.onTap, required this.titleText, required this.subtitleText, this.needBorderBelow = false, this.needEditButton = true});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -95,7 +100,7 @@ class CustomProfileOptionsTile extends StatelessWidget {
subtitleText.toText(fontSize: 12, color: MyColors.darkTextColor.withOpacity(0.7)), subtitleText.toText(fontSize: 12, color: MyColors.darkTextColor.withOpacity(0.7)),
], ],
), ),
const Icon(Icons.edit_note, size: 25), if (needEditButton) ...[MyAssets.icEdit.buildSvg()],
], ],
).onPress(onTap), ).onPress(onTap),
5.height, 5.height,

@ -0,0 +1,199 @@
import 'dart:async';
import 'dart:developer';
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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/shipping_models/shipping_status_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/utils/utils.dart';
import 'package:mc_common_app/view_models/shipping_management_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.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/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class ShippingManagementView extends StatefulWidget {
const ShippingManagementView({super.key});
@override
State<ShippingManagementView> createState() => _ShippingManagementViewState();
}
class _ShippingManagementViewState extends State<ShippingManagementView> {
late ShippingManagementVM shippingViewModel;
@override
void initState() {
shippingViewModel = context.read<ShippingManagementVM>();
scheduleMicrotask(() async {
if (shippingViewModel.shippingRequestFilterOptions.isNotEmpty) {
await shippingViewModel.populateShippingRequestFilterList();
}
await shippingViewModel.getShippingRequestsListByFilters();
});
super.initState();
}
Future buildUpdateShippingStatusBottomSheet({required int shippingRequestId}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, ShippingManagementVM shippingManagementVM, Widget? child) {
return InfoBottomSheet(
title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
ListView.separated(
shrinkWrap: true,
itemCount: shippingManagementVM.shippingRequestStatusesList.length,
separatorBuilder: (BuildContext context, int index) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 3.0),
child: Divider(thickness: 0.5),
);
},
itemBuilder: (BuildContext context, int index) {
List<FilterListModel> list = shippingManagementVM.shippingRequestStatusesList;
FilterListModel shippingFilterListModel = list[index];
return CircleCheckBoxWithTitle(
isChecked: shippingFilterListModel.isSelected,
title: shippingFilterListModel.title,
onSelected: () {
shippingManagementVM.updateSelectionInShippingRequestStatuses(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
12.height,
TxtField(
maxLines: 4,
value: shippingManagementVM.requestStatusComments,
errorValue: "",
keyboardType: TextInputType.text,
hint: LocaleKeys.comment.tr(),
onChanged: (v) => shippingManagementVM.updateRequestStatusComments(v),
),
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () async {
FilterListModel value = shippingManagementVM.shippingRequestStatusesList.firstWhere((element) => element.isSelected);
ShippingRequestStatusEnum shippingStatusEnum = value.id.toShippingStatusEnum();
bool status = await shippingManagementVM.onUpdateShippingStatusTapped(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId, context: context);
if (status) {
pop(context);
await shippingManagementVM.getShippingRequestsListByFilters();
}
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
@override
void dispose() {
shippingViewModel.resetFilters();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, ShippingManagementVM shippingVm, Widget? child) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.shippingManagement.tr()),
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Column(
children: [
16.height,
FiltersList(
filterList: shippingVm.shippingRequestFilterOptions,
onFilterTapped: (index, selectedFilterId) {
shippingVm.applyFiltersOnShippingRequests(shippingRequestStatusEnum: selectedFilterId.toShippingStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async {
int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected);
await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: index.toShippingStatusEnum());
},
child: (shippingVm.state == ViewState.busy)
? const Center(
child: CircularProgressIndicator(),
)
: shippingVm.shippingRequestsList.isEmpty
? Center(child: LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: shippingVm.shippingRequestsList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
ShippingRequestModel shippingRequest = shippingVm.shippingRequestsList[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(
text: Utils.getNameByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
chipColor: Utils.getChipColorByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
),
("Request Name | ${shippingRequest.id.toString()}").toText(fontSize: 16),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
"customer name".toText(color: MyColors.lightTextColor, fontSize: 14),
if (shippingRequest.createdOn != null && shippingRequest.createdOn!.isNotEmpty) ...[
" | ${DateTime.parse(shippingRequest.createdOn!).getTimeAgo()}".toText(color: MyColors.lightTextColor, fontSize: 14),
],
],
),
const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18),
],
),
],
).onPress(() {
buildUpdateShippingStatusBottomSheet(shippingRequestId: shippingRequest.id!);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
)),
],
),
));
});
}
}

@ -31,7 +31,9 @@ class _ChangeEmailPageState extends State<ChangeEmailPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changeEmail.tr()), appBar: CustomAppBar(
title: LocaleKeys.changeEmail.tr(),
),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Container( child: Container(
// width: double.infinity, // width: double.infinity,
@ -39,7 +41,11 @@ class _ChangeEmailPageState extends State<ChangeEmailPage> {
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: Column( child: Column(
children: [ children: [
LocaleKeys.enterEmail.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), LocaleKeys.enterEmail.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height, 12.height,
TxtField( TxtField(
hint: LocaleKeys.enterNewEmail.tr(), hint: LocaleKeys.enterNewEmail.tr(),

@ -31,15 +31,19 @@ class _ChangeMobilePageState extends State<ChangeMobilePage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changeMobile.tr()), appBar: CustomAppBar(title: LocaleKeys.changeMobile.tr()),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Container( child: Container(
// width: double.infinity, // width: double.infinity,
// height: double.infinity, // height: double.infinity,
padding: EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: Column( child: Column(
children: [ children: [
LocaleKeys.enterNewPhoneNumber.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), LocaleKeys.enterNewPhoneNumber.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height, 12.height,
TxtField( TxtField(
hint: LocaleKeys.enterNewPhoneNumber.tr(), hint: LocaleKeys.enterNewPhoneNumber.tr(),

@ -31,7 +31,7 @@ class _ChangePasswordPageState extends State<ChangePasswordPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changePassword.tr()), appBar: CustomAppBar(title: LocaleKeys.changePassword.tr()),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Container( child: Container(
// width: double.infinity, // width: double.infinity,
@ -39,7 +39,11 @@ class _ChangePasswordPageState extends State<ChangePasswordPage> {
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: Column( child: Column(
children: [ children: [
LocaleKeys.enterNewPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), LocaleKeys.enterNewPassword.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height, 12.height,
TxtField( TxtField(
hint: LocaleKeys.enterOldPassword.tr(), hint: LocaleKeys.enterOldPassword.tr(),

@ -73,7 +73,6 @@ class _EditAccountPageState extends State<EditAccountPage> {
), ),
], ],
).toWhiteContainer(width: double.infinity, pading: EdgeInsets.symmetric(horizontal: 12)), ).toWhiteContainer(width: double.infinity, pading: EdgeInsets.symmetric(horizontal: 12)),
Column( Column(
children: [ children: [
CustomSettingOptionsTile( CustomSettingOptionsTile(

@ -35,9 +35,8 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
//TODO: ONLY FOR DEVELOPMENT PURPOSE //TODO: ONLY FOR DEVELOPMENT PURPOSE
// String phoneNum = "966504278212", password = "Fa@1234"; // String phoneNum = "966504278212", password = "Fa@1234";
// String phoneNum = "966504278213", password = "Fa@1234"; // String phoneNum = "966504278213", password = "Fa@1234";
String phoneNum = "", password = "";
// String phoneNum = "", password = ""; String phoneNum = "", password = "";
String email = ""; String email = "";
String countryCode = ""; String countryCode = "";
Country? _country; Country? _country;
@ -52,23 +51,26 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
scheduleMicrotask(() { scheduleMicrotask(() {
userVM = Provider.of(context, listen: false); userVM = Provider.of(context, listen: false);
context.read<UserVM>().getAvailBio(); context.read<UserVM>().getAvailBio();
// if (AppState().currentAppType == AppType.provider) { if (AppState().currentAppType == AppType.provider) {
// phoneNum = "966530896018"; // phoneNum = "966530896018";
// password = "Amir@1234"; // password = "Amir@1234";
// // //
// // // phoneNum = "966569755630"; // phoneNum = "966530896020"; // JAMES BOND
// // // password = "Amir12345@"; //AAmir Sal // password = "Amir@1234";
// // //
// // // phoneNum = "966598646795"; // // phoneNum = "966569755630";
// // // password = "Zahoor@123"; // // password = "Amir12345@"; //AAmir Sal
// // //
// // // User Details // // phoneNum = "966598646795";
// // // phoneNum = "966554870506"; // // password = "Zahoor@123";
// // // password = "Sikander123@"; // "lastName": "sik", //
// // // "email": "sikander@gmail.com", // // User Details
// // // phoneNum = "966569755630"; // // phoneNum = "966554870506";
// // // password = "Amir12345@"; // // password = "Sikander123@"; // "lastName": "sik",
// } // // "email": "sikander@gmail.com",
// // phoneNum = "966569755630";
// // password = "Amir12345@";
}
getCountryList(); getCountryList();
}); });
@ -91,7 +93,12 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
child: Column( child: Column(
children: [ children: [
12.height, 12.height,
LocaleKeys.login.tr().toText( (AppState().currentAppType == AppType.provider ? "Provider" : "Customer").toText(
fontSize: 25,
letterSpacing: -1.44,
),
8.height,
(LocaleKeys.login.tr()).toText(
fontSize: 20, fontSize: 20,
letterSpacing: -1.44, letterSpacing: -1.44,
), ),

@ -1,10 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:sizer/sizer.dart';
class DropValue { class DropValue {
int id; int id;
@ -55,14 +55,16 @@ class _DropdownFieldState extends State<DropdownField> {
dropdownValue = widget.dropdownValue; dropdownValue = widget.dropdownValue;
return Column( return Column(
children: [ children: [
Container( IgnorePointer(
decoration: widget.showAppointmentPickerVariant ? null : Utils.containerColorRadiusBorderWidth(MyColors.white, 0, MyColors.darkPrimaryColor, 2), ignoring: !widget.isSelectAble,
child: Container(
decoration: widget.showAppointmentPickerVariant ? null : Utils.containerColorRadiusBorderWidth(MyColors.white, 0, widget.isSelectAble ? MyColors.darkPrimaryColor : MyColors.greyACColor, 2),
margin: const EdgeInsets.all(0), margin: const EdgeInsets.all(0),
padding: const EdgeInsets.only(left: 8, right: 8), padding: const EdgeInsets.only(left: 8, right: 8),
width: widget.showAppointmentPickerVariant ? 170 : null, width: widget.showAppointmentPickerVariant ? 170 : null,
child: DropdownButton<DropValue>( child: DropdownButton<DropValue>(
value: dropdownValue, value: dropdownValue,
icon: const Icon(Icons.keyboard_arrow_down_sharp), icon: Icon(Icons.keyboard_arrow_down_sharp, color: !widget.isSelectAble ? Colors.transparent : null),
elevation: 16, elevation: 16,
iconSize: widget.showAppointmentPickerVariant ? 26 : 16, iconSize: widget.showAppointmentPickerVariant ? 26 : 16,
iconEnabledColor: borderColor, iconEnabledColor: borderColor,
@ -91,6 +93,7 @@ class _DropdownFieldState extends State<DropdownField> {
).toList(), ).toList(),
), ),
), ),
),
if (widget.errorValue != "") if (widget.errorValue != "")
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,

@ -337,7 +337,6 @@ extension xDouble on int {
extension BuildSVG on String? { extension BuildSVG on String? {
Widget buildFileImage({double? height, double? width, BoxFit fit = BoxFit.contain, Color? color}) { Widget buildFileImage({double? height, double? width, BoxFit fit = BoxFit.contain, Color? color}) {
logger.i("!File(this!).existsSync(): ${!File(this!).existsSync()}");
if (this == null || this!.isEmpty || !File(this!).existsSync()) { if (this == null || this!.isEmpty || !File(this!).existsSync()) {
return SizedBox( return SizedBox(
height: height, height: height,
@ -369,14 +368,19 @@ extension BuildSVG on String? {
return SizedBox( return SizedBox(
height: height, height: height,
width: width, width: width,
child: SvgPicture.asset(MyAssets.providersIcon, color: MyColors.darkPrimaryColor).paddingAll(15), child: Image.asset(MyAssets.brokenImage).paddingAll(10),
); );
} }
return Image.network( return Image.network(
this!, this!,
errorBuilder: (BuildContext context, Object obj, StackTrace? s) { errorBuilder: (BuildContext context, Object obj, StackTrace? s) {
return SizedBox(height: height, width: width, child: const Icon(Icons.signal_wifi_connected_no_internet_4_outlined)); return Container(
height: height,
width: width,
decoration: BoxDecoration(border: Border.all(color: MyColors.roundedCrossBgColor)),
child: const Icon(Icons.image_not_supported_outlined, color: MyColors.roundedCrossBgColor),
);
}, },
loadingBuilder: (BuildContext context, Widget? child, ImageChunkEvent? imageChunk) { loadingBuilder: (BuildContext context, Widget? child, ImageChunkEvent? imageChunk) {
if (imageChunk == null) { if (imageChunk == null) {

@ -0,0 +1,114 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class MediaViewerScreen extends StatefulWidget {
final List<MessageImageModel> images; // List of image URLs or file paths
const MediaViewerScreen({Key? key, required this.images}) : super(key: key);
@override
MediaViewerScreenState createState() => MediaViewerScreenState();
}
class MediaViewerScreenState extends State<MediaViewerScreen> {
int selectedIndex = 0; // Track selected image index
@override
Widget build(BuildContext context) {
debugPrint("loaded");
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.pictures.tr()),
body: Column(
children: [
// Main Image Display (selected image)
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: InteractiveViewer(
panEnabled: true,
// Allow panning
scaleEnabled: true,
// Allow zooming
minScale: 1.0,
// Minimum zoom level
maxScale: 4.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: (widget.images[selectedIndex].isFromNetwork ?? false)
? widget.images[selectedIndex].imageUrl.buildNetworkImage(
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
)
: widget.images[selectedIndex].imagePath.buildFileImage(
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
),
),
),
),
// Thumbnail List at the bottom
Container(
height: 100, // Set height for thumbnail list
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.images.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index; // Change the selected image
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Container(
width: 80, // Thumbnail size
height: 80,
decoration: BoxDecoration(
border: Border.all(
color: selectedIndex == index ? MyColors.darkPrimaryColor : MyColors.greyShadowColor, // Highlight selected image
width: selectedIndex == index ? 2 : 1,
),
borderRadius: BorderRadius.circular(10),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: (widget.images[index].isFromNetwork ?? false)
? widget.images[index].imageUrl.buildNetworkImage(
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
)
: widget.images[index].imagePath.buildFileImage(
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
),
),
);
},
),
),
10.height,
],
),
);
}
}
Loading…
Cancel
Save