Merge branch 'localization_aamir' into faiz_development_common

master_new_changes
Faiz Hashmi 1 year ago
commit 7f0df61ff0

@ -509,7 +509,68 @@
"selectCategory": "اختر الفئة",
"searchByService": "البحث حسب الخدمة",
"selectServices": "اختر الخدمات",
"modifyPackage": "تعديل الحزمة"
"modifyPackage": "تعديل الحزمة",
"schedule": "الجدول",
"serviceLocation": "موقع الخدمة:",
"workshop": "ورشة العمل",
"itemsSelected": "العناصر المحددة",
"workshopFullAccessServices": "بعض الخدمات غير متوفرة في الموقع المنزلي. قم بتغيير الموقع إلى ورشة العمل للوصول الكامل إلى الخدمات",
"changeLocationService": "تغيير الموقع أو الخدمة:",
"noItemstoShow": "لا توجد عناصر لعرضها.",
"someDescriptionSubServices": "بعض الوصف عن الخدمات الفرعية",
"selectServicesYouWant": "اختر الخدمات التي تريدها",
"selectServiceType": "اختر نوع الخدمة",
"selectDateAndTime": "اختر التاريخ والوقت",
"reviewAppointment": "مراجعة الموعد",
"carEngineCheck": "فحص محرك السيارة",
"dateAndTime": "التاريخ والوقت",
"timeLocation": "الوقت والموقع",
"serviceCharges": "رسوم الخدمة",
"locationCharges": "رسوم الموقع",
"payableNow": "المبلغ المستحق الآن",
"remainingAmount": "المبلغ المتبقي",
"branchesFilter": "تصفية الفروع",
"searchByDistance": "البحث حسب المسافة",
"searchByMinimumRatings": "البحث حسب التقييمات الأدنى",
"chat": "الدردشة",
"noRequestsShow": "لا توجد طلبات لعرضها.",
"typeMessageHere": "اكتب رسالتك هنا..",
"reject": "رفض",
"newOfferRequired": "مطلوب عرض جديد",
"offerHasBeenAccepted": "تم قبول العرض",
"offerHasBeenRejected": "تم رفض العرض",
"offerHasBeenCancelled": "تم إلغاء العرض",
"paymentMethod": "طريقة الدفع",
"selectPaymentMethod": "اختر طريقة الدفع",
"password": "كلمة المرور",
"customerName": "اسم العميل",
"createRequest": "إنشاء طلب",
"requestType": "نوع الطلب",
"brand": "العلامة التجارية",
"year": "السنة",
"price": "السعر",
"shippingDelivery": "الشحن/التسليم",
"offers": "العروض",
"noOffersShow": "لا توجد عروض لعرضها",
"allDocumentMandatoryDealershipProvider": "جميع المستندات إلزامية لمقدم خدمات الوكالة",
"documentsUploadedSuccessfully": "تم تحميل المستندات بنجاح",
"help": "المساعدة",
"faqs": "الأسئلة الشائعة",
"contactUs": "اتصل بنا",
"termPrivacy": "الشروط والخصوصية",
"inviteFriends": "دعوة الأصدقاء",
"more": "المزيد",
"language": "اللغة",
"mySubscriptions": "اشتراكاتي",
"subscriptions": "الاشتراكات",
"defineLicenses": "تحديد التراخيص",
"logOut": "تسجيل الخروج",
"customer": "العميل",
"accept": "قبول"

@ -510,14 +510,62 @@
"selectCategory":"Select Category",
"searchByService":"Search By Service",
"selectServices":"Select Services",
"modifyPackage": "Modify Package"
"modifyPackage": "Modify Package",
"schedule": "Schedule",
"serviceLocation": "Service Location:",
"workshop": "Workshop",
"itemsSelected": "Item(s) Selected",
"workshopFullAccessServices": "Few services are not available on home location. Change the location to workshop to full access the services",
"changeLocationService": "Change location or service:",
"noItemstoShow": "No Items to show.",
"someDescriptionSubServices": "Some description about the sub-services",
"selectServicesYouWant": "Select services you want",
"selectServiceType": "Select service type",
"selectDateAndTime": "Select date and time",
"reviewAppointment": "Review Appointment",
"carEngineCheck": "Car Engine Check",
"dateAndTime": "Date and Time",
"timeLocation": "Time & Location",
"serviceCharges": "Service Charges",
"locationCharges" : "Location Charges",
"payableNow": "Payable Now",
"remainingAmount": "Remaining Amount",
"branchesFilter": "Branches Filter",
"searchByDistance": "Search By Distance",
"searchByMinimumRatings": "Search By Minimum Ratings",
"chat": "Chat",
"noRequestsShow": "No Requests to show.",
"typeMessageHere": "Type your message here..",
"reject": "Reject",
"newOfferRequired": "New Offer Required",
"offerHasBeenAccepted": "Offer has been accepted",
"offerHasBeenRejected": "Offer has been rejected",
"offerHasBeenCancelled": "Offer has been cancelled",
"paymentMethod": "Payment Method",
"selectPaymentMethod": "Select Payment Method",
"password": "Password",
"customerName": "Customer Name",
"createRequest": "Create Request",
"requestType": "Request Type",
"brand": "Brand",
"year": "Year",
"price": "Price",
"shippingDelivery": "Shipping/Delivery",
"offers": "Offers",
"noOffersShow": "No Offers to show",
"allDocumentMandatoryDealershipProvider": "All document's are mandatory for Dealership Provider",
"documentsUploadedSuccessfully": "Documents uploaded successfully",
"help": "Help",
"faqs": "FAQs",
"contactUs": "Contact Us",
"termPrivacy": "Term & Privacy",
"inviteFriends": "Invite Friends",
"more": "More",
"language" :"Language",
"mySubscriptions": "My Subscriptions",
"subscriptions": "Subscriptions",
"defineLicenses": "Define Licenses",
"logOut": "Log Out",
"customer": "Customer",
"accept": "Accept"
}

@ -525,7 +525,64 @@ class CodegenLoader extends AssetLoader{
"selectCategory": "اختر الفئة",
"searchByService": "البحث حسب الخدمة",
"selectServices": "اختر الخدمات",
"modifyPackage": "تعديل الحزمة"
"modifyPackage": "تعديل الحزمة",
"schedule": "الجدول",
"serviceLocation": "موقع الخدمة:",
"workshop": "ورشة العمل",
"itemsSelected": "العناصر المحددة",
"workshopFullAccessServices": "بعض الخدمات غير متوفرة في الموقع المنزلي. قم بتغيير الموقع إلى ورشة العمل للوصول الكامل إلى الخدمات",
"changeLocationService": "تغيير الموقع أو الخدمة:",
"noItemstoShow": "لا توجد عناصر لعرضها.",
"someDescriptionSubServices": "بعض الوصف عن الخدمات الفرعية",
"selectServicesYouWant": "اختر الخدمات التي تريدها",
"selectServiceType": "اختر نوع الخدمة",
"selectDateAndTime": "اختر التاريخ والوقت",
"reviewAppointment": "مراجعة الموعد",
"carEngineCheck": "فحص محرك السيارة",
"dateAndTime": "التاريخ والوقت",
"timeLocation": "الوقت والموقع",
"serviceCharges": "رسوم الخدمة",
"locationCharges": "رسوم الموقع",
"payableNow": "المبلغ المستحق الآن",
"remainingAmount": "المبلغ المتبقي",
"branchesFilter": "تصفية الفروع",
"searchByDistance": "البحث حسب المسافة",
"searchByMinimumRatings": "البحث حسب التقييمات الأدنى",
"chat": "الدردشة",
"noRequestsShow": "لا توجد طلبات لعرضها.",
"typeMessageHere": "اكتب رسالتك هنا..",
"reject": "رفض",
"newOfferRequired": "مطلوب عرض جديد",
"offerHasBeenAccepted": "تم قبول العرض",
"offerHasBeenRejected": "تم رفض العرض",
"offerHasBeenCancelled": "تم إلغاء العرض",
"paymentMethod": "طريقة الدفع",
"selectPaymentMethod": "اختر طريقة الدفع",
"password": "كلمة المرور",
"customerName": "اسم العميل",
"createRequest": "إنشاء طلب",
"requestType": "نوع الطلب",
"brand": "العلامة التجارية",
"year": "السنة",
"price": "السعر",
"shippingDelivery": "الشحن/التسليم",
"offers": "العروض",
"noOffersShow": "لا توجد عروض لعرضها",
"allDocumentMandatoryDealershipProvider": "جميع المستندات إلزامية لمقدم خدمات الوكالة",
"documentsUploadedSuccessfully": "تم تحميل المستندات بنجاح",
"help": "المساعدة",
"faqs": "الأسئلة الشائعة",
"contactUs": "اتصل بنا",
"termPrivacy": "الشروط والخصوصية",
"inviteFriends": "دعوة الأصدقاء",
"more": "المزيد",
"language": "اللغة",
"mySubscriptions": "اشتراكاتي",
"subscriptions": "الاشتراكات",
"defineLicenses": "تحديد التراخيص",
"logOut": "تسجيل الخروج",
"customer": "العميل",
"accept": "قبول"
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1039,7 +1096,64 @@ static const Map<String,dynamic> en_US = {
"selectCategory": "Select Category",
"searchByService": "Search By Service",
"selectServices": "Select Services",
"modifyPackage": "Modify Package"
"modifyPackage": "Modify Package",
"schedule": "Schedule",
"serviceLocation": "Service Location:",
"workshop": "Workshop",
"itemsSelected": "Item(s) Selected",
"workshopFullAccessServices": "Few services are not available on home location. Change the location to workshop to full access the services",
"changeLocationService": "Change location or service:",
"noItemstoShow": "No Items to show.",
"someDescriptionSubServices": "Some description about the sub-services",
"selectServicesYouWant": "Select services you want",
"selectServiceType": "Select service type",
"selectDateAndTime": "Select date and time",
"reviewAppointment": "Review Appointment",
"carEngineCheck": "Car Engine Check",
"dateAndTime": "Date and Time",
"timeLocation": "Time & Location",
"serviceCharges": "Service Charges",
"locationCharges": "Location Charges",
"payableNow": "Payable Now",
"remainingAmount": "Remaining Amount",
"branchesFilter": "Branches Filter",
"searchByDistance": "Search By Distance",
"searchByMinimumRatings": "Search By Minimum Ratings",
"chat": "Chat",
"noRequestsShow": "No Requests to show.",
"typeMessageHere": "Type your message here..",
"reject": "Reject",
"newOfferRequired": "New Offer Required",
"offerHasBeenAccepted": "Offer has been accepted",
"offerHasBeenRejected": "Offer has been rejected",
"offerHasBeenCancelled": "Offer has been cancelled",
"paymentMethod": "Payment Method",
"selectPaymentMethod": "Select Payment Method",
"password": "Password",
"customerName": "Customer Name",
"createRequest": "Create Request",
"requestType": "Request Type",
"brand": "Brand",
"year": "Year",
"price": "Price",
"shippingDelivery": "Shipping/Delivery",
"offers": "Offers",
"noOffersShow": "No Offers to show",
"allDocumentMandatoryDealershipProvider": "All document's are mandatory for Dealership Provider",
"documentsUploadedSuccessfully": "Documents uploaded successfully",
"help": "Help",
"faqs": "FAQs",
"contactUs": "Contact Us",
"termPrivacy": "Term & Privacy",
"inviteFriends": "Invite Friends",
"more": "More",
"language": "Language",
"mySubscriptions": "My Subscriptions",
"subscriptions": "Subscriptions",
"defineLicenses": "Define Licenses",
"logOut": "Log Out",
"customer": "Customer",
"accept": "Accept"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -489,5 +489,62 @@ abstract class LocaleKeys {
static const searchByService = 'searchByService';
static const selectServices = 'selectServices';
static const modifyPackage = 'modifyPackage';
static const schedule = 'schedule';
static const serviceLocation = 'serviceLocation';
static const workshop = 'workshop';
static const itemsSelected = 'itemsSelected';
static const workshopFullAccessServices = 'workshopFullAccessServices';
static const changeLocationService = 'changeLocationService';
static const noItemstoShow = 'noItemstoShow';
static const someDescriptionSubServices = 'someDescriptionSubServices';
static const selectServicesYouWant = 'selectServicesYouWant';
static const selectServiceType = 'selectServiceType';
static const selectDateAndTime = 'selectDateAndTime';
static const reviewAppointment = 'reviewAppointment';
static const carEngineCheck = 'carEngineCheck';
static const dateAndTime = 'dateAndTime';
static const timeLocation = 'timeLocation';
static const serviceCharges = 'serviceCharges';
static const locationCharges = 'locationCharges';
static const payableNow = 'payableNow';
static const remainingAmount = 'remainingAmount';
static const branchesFilter = 'branchesFilter';
static const searchByDistance = 'searchByDistance';
static const searchByMinimumRatings = 'searchByMinimumRatings';
static const chat = 'chat';
static const noRequestsShow = 'noRequestsShow';
static const typeMessageHere = 'typeMessageHere';
static const reject = 'reject';
static const newOfferRequired = 'newOfferRequired';
static const offerHasBeenAccepted = 'offerHasBeenAccepted';
static const offerHasBeenRejected = 'offerHasBeenRejected';
static const offerHasBeenCancelled = 'offerHasBeenCancelled';
static const paymentMethod = 'paymentMethod';
static const selectPaymentMethod = 'selectPaymentMethod';
static const password = 'password';
static const customerName = 'customerName';
static const createRequest = 'createRequest';
static const requestType = 'requestType';
static const brand = 'brand';
static const year = 'year';
static const price = 'price';
static const shippingDelivery = 'shippingDelivery';
static const offers = 'offers';
static const noOffersShow = 'noOffersShow';
static const allDocumentMandatoryDealershipProvider = 'allDocumentMandatoryDealershipProvider';
static const documentsUploadedSuccessfully = 'documentsUploadedSuccessfully';
static const help = 'help';
static const faqs = 'faqs';
static const contactUs = 'contactUs';
static const termPrivacy = 'termPrivacy';
static const inviteFriends = 'inviteFriends';
static const more = 'more';
static const language = 'language';
static const mySubscriptions = 'mySubscriptions';
static const subscriptions = 'subscriptions';
static const defineLicenses = 'defineLicenses';
static const logOut = 'logOut';
static const customer = 'customer';
static const accept = 'accept';
}

@ -27,15 +27,13 @@ class SubscriptionsVM extends BaseVM {
getAllAvailableSubscriptions(String? serviceProviderID) async {
selectedIndex = 0;
setState(ViewState.busy);
allSubscriptions =
await subscriptionRepo.getAllSubscriptions(serviceProviderID);
allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID);
if (allSubscriptions.messageStatus == 1) {
monthlyTabs.clear();
var idSet = <int>{};
for (var d in allSubscriptions.data ?? []) {
if (idSet.add(d.durationDays ?? 0)) {
monthlyTabs.add(DropValue(
d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), ""));
monthlyTabs.add(DropValue(d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), ""));
}
}
monthlyTabs.sort((a, b) => a.value.compareTo(b.value));
@ -50,15 +48,13 @@ class SubscriptionsVM extends BaseVM {
getSubscriptionBySP(String serviceProviderID, bool isRenew) async {
selectedIndex = 0;
setState(ViewState.busy);
allSubscriptions =
await subscriptionRepo.getSubscriptionBySP(serviceProviderID, isRenew);
allSubscriptions = await subscriptionRepo.getSubscriptionBySP(serviceProviderID, isRenew);
if (allSubscriptions.messageStatus == 1) {
monthlyTabs.clear();
var idSet = <int>{};
for (var d in allSubscriptions.data ?? []) {
if (idSet.add(d.durationDays ?? 0)) {
monthlyTabs.add(DropValue(
d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), ""));
monthlyTabs.add(DropValue(d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), ""));
}
}
monthlyTabs.sort((a, b) => a.value.compareTo(b.value));
@ -72,11 +68,9 @@ class SubscriptionsVM extends BaseVM {
String newPrice = "";
calculationUpgradePrice(
String? serviceProviderID, String? newSubscription) async {
calculationUpgradePrice(String? serviceProviderID, String? newSubscription) async {
setState(ViewState.busy);
MResponse mResponse = await subscriptionRepo.calculationUpgradePrice(
serviceProviderID, newSubscription);
MResponse mResponse = await subscriptionRepo.calculationUpgradePrice(serviceProviderID, newSubscription);
if (mResponse.messageStatus == 1) {
setState(ViewState.idle);
newPrice = mResponse.data.toString();
@ -85,18 +79,13 @@ class SubscriptionsVM extends BaseVM {
}
}
Future<MResponse> payForSubscription(
int subscriptionId, bool isStartNow, bool isReview, String amount,
{bool isDegrade = false,
List<int>? listOfBranches,
List<int>? listOfUsers}) async {
Future<MResponse> payForSubscription(int subscriptionId, bool isStartNow, bool isReview, String amount, {bool isDegrade = false, List<int>? listOfBranches, List<int>? listOfUsers}) async {
Map<String, dynamic> map;
if (isDegrade) {
map = {
// "id": subscription.id.toString(),
// "payFortOrderID": 0,
"providerID":
AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"subscriptionID": subscriptionId.toString(),
"isStartNow": isStartNow.toString(),
"subscriptionAmount": amount,
@ -108,8 +97,7 @@ class SubscriptionsVM extends BaseVM {
map = {
// "id": subscription.id.toString(),
// "payFortOrderID": 0,
"providerID":
AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"subscriptionID": subscriptionId.toString(),
"isStartNow": isStartNow.toString(),
"subscriptionAmount": amount,
@ -118,8 +106,23 @@ class SubscriptionsVM extends BaseVM {
// "listOfUsers": []
};
}
MResponse mResponse =
await subscriptionRepo.payForProviderSubscription(map);
MResponse mResponse = await subscriptionRepo.payForProviderSubscription(map);
return mResponse;
}
Future<MResponse> createSubscriptionOrder(int subscriptionId, bool isStartNow, bool isReview, String amount, {bool isDegrade = false, List<int>? listOfBranches, List<int>? listOfUsers}) async {
Map<String, dynamic> map = {
// "id": subscription.id.toString(),
// "payFortOrderID": 0,
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"subscriptionID": subscriptionId.toString(),
"isStartNow": isStartNow.toString(),
"subscriptionAmount": amount,
"isRenew": isReview.toString()
// "listOfBranches": [],
// "listOfUsers": []
};
MResponse mResponse = await subscriptionRepo.payForProviderSubscription(map);
return mResponse;
}
@ -130,8 +133,7 @@ class SubscriptionsVM extends BaseVM {
Map<String, String> map = {
// "id": subscription.id.toString(),
// "payFortOrderID": 0,
"providerID":
AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
// "listOfBranches": [],
// "listOfUsers": []
};
@ -146,12 +148,8 @@ class SubscriptionsVM extends BaseVM {
final int months = days ~/ 30;
final int remainingDays = days % 30;
String _result = months > 0
? '$months Month${months > 1 ? 's' : ''}${remainingDays > 0 ? ' & ' : ''}'
: '';
_result += remainingDays > 0
? '$remainingDays Day${remainingDays > 1 ? 's' : ''}'
: '';
String _result = months > 0 ? '$months Month${months > 1 ? 's' : ''}${remainingDays > 0 ? ' & ' : ''}' : '';
_result += remainingDays > 0 ? '$remainingDays Day${remainingDays > 1 ? 's' : ''}' : '';
return _result;
}
@ -169,8 +167,7 @@ class SubscriptionsVM extends BaseVM {
selectedIndex = 0;
setState(ViewState.busy);
// allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID);
allSubscriptions =
await subscriptionRepo.getMySubscriptions(serviceProviderID);
allSubscriptions = await subscriptionRepo.getMySubscriptions(serviceProviderID);
if (allSubscriptions.messageStatus == 1) {
// allSubscriptions.data!.sort((a, b) => a.value.compareTo(b.value));
setState(ViewState.idle);

@ -53,6 +53,14 @@ class UserVM extends BaseVM {
bool completeProfilePageCheckbox = false;
bool _loginOtherAccount = false;
bool get loginOtherAccount => _loginOtherAccount;
set loginOtherAccount(bool value) {
_loginOtherAccount = value;
}
void updateCompleteProfilePageCheckbox(bool newValue) {
completeProfilePageCheckbox = newValue;
notifyListeners();
@ -155,8 +163,7 @@ class UserVM extends BaseVM {
}
}
Future<void> performCompleteProfile(
BuildContext context, {
Future<void> performCompleteProfile(BuildContext context, {
required String password,
required String confirmPassword,
required String firstName,
@ -515,8 +522,8 @@ class UserVM extends BaseVM {
type == ClassType.NUMBER && countryCode != null
? countryCode + phoneNum
: type == ClassType.NUMBER && countryCode == null
? phoneNum
: phoneNum,
? phoneNum
: phoneNum,
password);
Utils.hideLoading(context);
LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body));
@ -524,8 +531,8 @@ class UserVM extends BaseVM {
SharedPrefManager.setPhoneOrEmail(type == ClassType.NUMBER && countryCode != null
? countryCode + phoneNum
: type == ClassType.NUMBER && countryCode == null
? phoneNum
: phoneNum);
? phoneNum
: phoneNum);
SharedPrefManager.setUserPassword(password);
navigateReplaceWithName(context, AppRoutes.loginMethodSelection, arguments: user.data!.userToken);
} else {
@ -620,9 +627,7 @@ class UserVM extends BaseVM {
Future<void> isAlreadyUserLoggedin(BuildContext context) async {
String uName = await SharedPrefManager.getPhoneOrEmail();
String pass = await SharedPrefManager.getUserPassword();
if (uName.isNotEmpty && pass.isNotEmpty) {
logger.d(uName);
if (!loginOtherAccount && uName.isNotEmpty && pass.isNotEmpty) {
if (uName.isNum()) {
performBasicOtpLoginWithPasswordPage(context, type: ClassType.NUMBER, countryCode: null, phoneNum: uName, password: pass);
}
@ -632,4 +637,9 @@ class UserVM extends BaseVM {
logger.d("Skip Login Triggered");
}
}
void otherLogin(BuildContext context) {
_loginOtherAccount = true;
navigateReplaceWithName(context, AppRoutes.loginWithPassword);
}
}

@ -1,6 +1,7 @@
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/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -11,6 +12,7 @@ import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class ScreenArgumentsForAppointmentDetailPage {
final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment
@ -28,7 +30,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Book Appointment",
title: LocaleKeys.bookAppointment.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
@ -52,15 +54,15 @@ class BookAppointmentSchedulesView extends StatelessWidget {
Row(
children: [
Expanded(
child: "Schedule ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
child: (LocaleKeys.schedule.tr() + " ${scheduleIndex + 1}").toText(fontSize: 20, isBold: true),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
("${scheduleData.appointmentType == 2 ? "Home" : "Workshop"}").toText(fontSize: 12, isBold: true).expand(),
(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(),
],
),
Column(
@ -100,7 +102,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
("Available Slots").toText(fontSize: 14, isBold: true),
(LocaleKeys.availableSlots.tr()).toText(fontSize: 14, isBold: true),
],
),
5.height,
@ -128,7 +130,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
title: LocaleKeys.cancel.tr(),
onPressed: () => Navigator.pop(context),
backgroundColor: MyColors.greyButtonColor,
),
@ -137,7 +139,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? "Review" : "Confirm",
title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? LocaleKeys.review.tr() : LocaleKeys.confirm.tr(),
onPressed: () {
if (screenArgumentsForAppointmentDetailPage.routeFlag == 1) {
appointmentsVM.onReviewButtonPressed(context);

@ -1,6 +1,9 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.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/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -10,6 +13,7 @@ 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';
import 'package:easy_localization/easy_localization.dart';
class BookAppointmentServicesView extends StatelessWidget {
BookAppointmentServicesView({Key? key}) : super(key: key);
@ -18,7 +22,7 @@ class BookAppointmentServicesView extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Book Appointment",
title: LocaleKeys.bookAppointment.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () {
@ -27,7 +31,8 @@ class BookAppointmentServicesView extends StatelessWidget {
},
),
body: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
builder: (BuildContext context, AppointmentsVM appointmentsVM,
Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -35,12 +40,14 @@ class BookAppointmentServicesView extends StatelessWidget {
CustomAddButton(
needsBorder: true,
bgColor: MyColors.white,
onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM),
text: "Add Services",
onTap: () => appointmentsVM.openTheAddServiceBottomSheet(
context, appointmentsVM),
text: LocaleKeys.addServices.tr(),
icon: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).horPaddingMain(),
@ -49,17 +56,22 @@ class BookAppointmentServicesView extends StatelessWidget {
shrinkWrap: true,
itemCount: appointmentsVM.servicesInCurrentAppointment.length,
itemBuilder: (BuildContext context, int serviceIndex) {
ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex];
ServiceModel serviceData = appointmentsVM
.servicesInCurrentAppointment[serviceIndex];
return Column(
children: [
Row(
children: [
Expanded(
child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true),
child: (serviceData.serviceDescription ?? "")
.toText(fontSize: 15, isBold: true),
),
IconButton(
onPressed: () => appointmentsVM.removeServiceInCurrentAppointment(serviceIndex),
icon: Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () => appointmentsVM
.removeServiceInCurrentAppointment(
serviceIndex),
icon: Icon(Icons.delete_outline,
color: MyColors.redColor),
)
],
),
@ -67,19 +79,33 @@ class BookAppointmentServicesView extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(serviceData.isHomeSelected ? serviceData.homeLocation : "Workshop").toText(fontSize: 12, isBold: true).expand(),
(LocaleKeys.serviceLocation.tr()).toText(
fontSize: 12,
color: MyColors.lightTextColor,
isBold: true),
(serviceData.isHomeSelected
? serviceData.homeLocation
: LocaleKeys.workshop.tr())
.toText(fontSize: 12, isBold: true)
.expand(),
],
),
5.height,
Column(
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData = serviceData.serviceItems![itemIndex];
children: List.generate(
serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData =
serviceData.serviceItems![itemIndex];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
"${itemData.name}: ".toText(
fontSize: 13,
color: MyColors.lightTextColor,
isBold: true),
("${itemData.price}")
.toText(fontSize: 13, isBold: true)
.expand(),
],
);
}),
@ -88,18 +114,33 @@ class BookAppointmentServicesView extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true),
((appointmentsVM
.servicesInCurrentAppointment[
serviceIndex]
.currentTotalServicePrice)
.toString())
.toText(fontSize: 32, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
LocaleKeys.sar
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 16,
isBold: true)
.paddingOnly(bottom: 5),
Icon(Icons.arrow_drop_down, size: 30)
],
).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])),
).onPress(() => appointmentsVM.priceBreakDownClicked(
context,
appointmentsVM
.servicesInCurrentAppointment[serviceIndex])),
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
).toWhiteContainer(
width: double.infinity,
allPading: 12,
margin: const EdgeInsets.symmetric(
horizontal: 21, vertical: 10));
},
).expand(),
Row(
@ -108,7 +149,7 @@ class BookAppointmentServicesView extends StatelessWidget {
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
title: LocaleKeys.cancel.tr(),
onPressed: () {
appointmentsVM.servicesInCurrentAppointment.clear();
appointmentsVM.allSelectedItemsInAppointments.clear();
@ -121,7 +162,7 @@ class BookAppointmentServicesView extends StatelessWidget {
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Next",
title: LocaleKeys.next.tr(),
onPressed: () {
appointmentsVM.onServicesNextPressed(context);
},

@ -1,8 +1,8 @@
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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
@ -12,6 +12,7 @@ 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';
import 'package:easy_localization/easy_localization.dart';
class BookAppointmentsItemView extends StatelessWidget {
const BookAppointmentsItemView({Key? key}) : super(key: key);
@ -20,14 +21,15 @@ class BookAppointmentsItemView extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Select Items",
title: LocaleKeys.selectItems.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context),
),
body: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
builder: (BuildContext context, AppointmentsVM appointmentsVM,
Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -36,18 +38,30 @@ class BookAppointmentsItemView extends StatelessWidget {
width: double.infinity,
color: MyColors.darkTextColor,
alignment: Alignment.centerLeft,
child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(),
child: ("${appointmentsVM.selectedSubServicesCounter} " +
LocaleKeys.itemsSelected.tr())
.toText(fontSize: 16, color: MyColors.white)
.horPaddingMain(),
),
16.height,
Column(
children: [
"Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor),
LocaleKeys.workshopFullAccessServices.tr().toText(
fontSize: 12,
isItalic: true,
color: MyColors.lightTextColor),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Change location or service: ".toText(fontSize: 14, isBold: true),
"Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor),
LocaleKeys.changeLocationService
.tr()
.toText(fontSize: 14, isBold: true),
LocaleKeys.edit.tr().toText(
fontSize: 14,
isBold: true,
isUnderLine: true,
color: MyColors.adPendingStatusColor),
5.width,
MyAssets.icEdit.buildSvg(width: 17),
],
@ -57,26 +71,41 @@ class BookAppointmentsItemView extends StatelessWidget {
],
).horPaddingMain(),
appointmentsVM.serviceItemsFromApi.isEmpty
? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
? Expanded(
child: Center(
child: LocaleKeys.noItemstoShow.toText(
fontSize: 16, color: MyColors.lightTextColor)))
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(),
separatorBuilder: (BuildContext context, int index) =>
Divider(),
itemCount: appointmentsVM.serviceItemsFromApi.length,
itemBuilder: (BuildContext context, int index) {
ItemData itemData = appointmentsVM.serviceItemsFromApi[index];
ItemData itemData =
appointmentsVM.serviceItemsFromApi[index];
return ServiceItemWithPriceCheckBox(
description: itemData.description ?? "Some description about the sub-services",
description: itemData.description ??
LocaleKeys.someDescriptionSubServices.tr(),
title: itemData.name!,
isSelected: itemData.isUpdateOrSelected!,
onSelection: (bool value) {
print("itemId: ${itemData.id}");
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
appointmentsVM.onItemUpdateOrSelected(index,
!itemData.isUpdateOrSelected!, itemData.id!);
},
priceWidget: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// TODO: This Price will be decided according to the service selected
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
" SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
itemData.price!
.split(".")
.first
.toText(fontSize: 30, isBold: true),
LocaleKeys.sar
.tr()
.toText(
fontSize: 15,
isBold: true,
color: MyColors.lightTextColor)
.paddingOnly(bottom: 5),
],
),
);
@ -93,7 +122,8 @@ class BookAppointmentsItemView extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red),
appointmentsVM.selectSubServicesError
.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10),
8.height,
@ -103,9 +133,10 @@ class BookAppointmentsItemView extends StatelessWidget {
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
title: LocaleKeys.cancel.tr(),
onPressed: () {
appointmentsVM.resetCategorySelectionBottomSheet();
appointmentsVM
.resetCategorySelectionBottomSheet();
pop(context);
},
backgroundColor: MyColors.greyButtonColor,
@ -117,9 +148,10 @@ class BookAppointmentsItemView extends StatelessWidget {
builder: (BuildContext context) {
return ShowFillButton(
maxHeight: 55,
title: "Next",
title: LocaleKeys.next.tr(),
onPressed: () async {
bool resp = appointmentsVM.validateItemsSelection();
bool resp =
appointmentsVM.validateItemsSelection();
if (resp) {
appointmentsVM.onItemsSelectedInService();
Navigator.pop(context);
@ -133,7 +165,10 @@ class BookAppointmentsItemView extends StatelessWidget {
// Navigator.of(context).pushReplacementNamed(AppRoutes.bookAppointmenServicesView);
// }
},
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
backgroundColor: !appointmentsVM
.isServiceSelectionValidated()
? MyColors.lightTextColor.withOpacity(0.6)
: MyColors.darkPrimaryColor,
);
},
),

@ -2,6 +2,7 @@ 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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
@ -9,6 +10,7 @@ import 'package:mc_common_app/widgets/common_widgets/provider_details_card.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/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart';
class BookProviderAppView extends StatefulWidget {
const BookProviderAppView({Key? key}) : super(key: key);
@ -24,7 +26,7 @@ class _BookProviderAppViewState extends State<BookProviderAppView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Appointment",
title: LocaleKeys.appointment.tr(),
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
@ -46,7 +48,9 @@ class _BookProviderAppViewState extends State<BookProviderAppView> {
providerRatings: "4.9",
),
12.height,
isReview ? ReviewAppointmentSection() : ServicesSelectionSection(),
isReview
? ReviewAppointmentSection()
: ServicesSelectionSection(),
10.height,
],
),
@ -55,7 +59,7 @@ class _BookProviderAppViewState extends State<BookProviderAppView> {
Padding(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: ShowFillButton(
title: "Book Appointment",
title: LocaleKeys.bookAppointment.tr(),
maxWidth: double.infinity,
onPressed: () {
isReview = !isReview;
@ -87,44 +91,47 @@ class ServicesSelectionSection extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Select services you want".toText(fontSize: 18, isBold: true),
LocaleKeys.selectServicesYouWant
.tr()
.toText(fontSize: 18, isBold: true),
8.height,
DropdownField(
(DropValue value) {},
list: dropList,
hint: "Select service type",
hint: LocaleKeys.selectServiceType.tr(),
),
8.height,
DropdownField(
(DropValue value) {},
list: dropList,
hint: "Select service type",
hint: LocaleKeys.selectServiceType.tr(),
),
8.height,
DropdownField(
(DropValue value) {},
list: dropList,
hint: "Select service type",
hint: LocaleKeys.selectServiceType.tr(),
),
22.height,
"Select date and time".toText(fontSize: 18, isBold: true),
LocaleKeys.selectDateAndTime.tr().toText(fontSize: 18, isBold: true),
8.height,
DropdownField(
(DropValue value) {},
list: dropList,
hint: "Select service type",
hint: LocaleKeys.selectServiceType.tr(),
),
22.height,
"Available slots".toText(fontSize: 15, isBold: true),
LocaleKeys.availableSlots.tr().toText(fontSize: 15, isBold: true),
8.height,
BuildTimeSlots(onPressed: (index) {}, timeSlots: []),
22.height,
"Total Amount".toText(fontSize: 18, isBold: true),
LocaleKeys.totalAmount.tr().toText(fontSize: 18, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"3000".toText(fontSize: 20, isBold: true),
"SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.sar.tr().toText(
fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
10.height,
@ -144,20 +151,24 @@ class ReviewAppointmentSection extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Review Appointment".toText(fontSize: 18, isBold: true),
LocaleKeys.reviewAppointment.tr().toText(fontSize: 18, isBold: true),
15.height,
"Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"Car Engine Check".toText(fontSize: 18, isBold: true),
LocaleKeys.services.tr().toText(
fontSize: 14, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.carEngineCheck.tr().toText(fontSize: 18, isBold: true),
13.height,
"Date and Time".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.dateAndTime.tr().toText(
fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true),
13.height,
"Total Amount".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.totalAmount.tr().toText(
fontSize: 14, isBold: true, color: MyColors.lightTextColor),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"3000".toText(fontSize: 20, isBold: true),
"SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.sar.tr().toText(
fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
100.height,

@ -1,6 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.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';
@ -48,12 +48,17 @@ class ReviewAppointment extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(appointmentsVM.selectedBranchModel!.branchName ?? "").toText(fontSize: 16, isBold: true),
(appointmentsVM.selectedBranchModel!.branchName ??
"")
.toText(fontSize: 16, isBold: true),
Row(
children: [
LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12),
LocaleKeys.location.tr().toText(
color: MyColors.lightTextColor,
fontSize: 12),
2.width,
": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}".toText(fontSize: 12),
": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}"
.toText(fontSize: 12),
],
),
],
@ -77,7 +82,9 @@ class ReviewAppointment extends StatelessWidget {
),
),
],
).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12));
)
.onPress(() {})
.toWhiteContainer(width: double.infinity, allPading: 12));
}
Widget buildServicesInfoCard({required BuildContext context}) {
@ -86,14 +93,18 @@ class ReviewAppointment extends StatelessWidget {
shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
ServiceAppointmentScheduleModel scheduleData =
appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
child: LocaleKeys.services.tr().toText(
fontSize: 14,
isBold: true,
color: MyColors.lightTextColor),
),
],
),
@ -106,33 +117,55 @@ class ReviewAppointment extends StatelessWidget {
itemCount: scheduleData.servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot;
if (scheduleData
.selectedCustomTimeDateSlotModel!.availableSlots !=
null) {
selectedTimeSlot = scheduleData
.selectedCustomTimeDateSlotModel!.availableSlots!
.firstWhere((element) => element.isSelected)
.slot;
}
return Column(
children: [
if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[
if (scheduleData
.servicesListInAppointment!.isNotEmpty) ...[
Column(
children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) {
ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex];
children: List.generate(
scheduleData.servicesListInAppointment!.length,
(serviceIndex) {
ServiceModel serviceData = scheduleData
.servicesListInAppointment![serviceIndex];
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
"${serviceData.providerServiceDescription}".toText(fontSize: 16, isBold: true),
"${serviceData.providerServiceDescription}"
.toText(fontSize: 16, isBold: true),
],
),
Column(
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData = serviceData.serviceItems![itemIndex];
children: List.generate(
serviceData.serviceItems!.length,
(itemIndex) {
ItemData itemData =
serviceData.serviceItems![itemIndex];
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
"${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor),
("${itemData.name}: ${itemData.price} " +
LocaleKeys.sar.tr())
.toText(
fontSize: 13,
isBold: true,
color: MyColors
.lightTextColor),
],
),
],
@ -150,15 +183,27 @@ class ReviewAppointment extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Time & Location".toText(fontSize: 16, isBold: true),
LocaleKeys.timeLocation
.tr()
.toText(fontSize: 16, isBold: true),
3.height,
Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}".toText(fontSize: 12, isBold: true),
LocaleKeys.dateAndTime.tr().toText(
fontSize: 12,
color: MyColors.lightTextColor,
isBold: true),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}"
.toText(fontSize: 12, isBold: true),
]),
Row(children: [
"Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(scheduleData.appointmentType == 2 ? "Home" : "Workshop").toText(fontSize: 12, 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),
]),
],
),
@ -174,20 +219,35 @@ class ReviewAppointment extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Amount".toText(fontSize: 16, isBold: true),
LocaleKeys.amount
.tr()
.toText(fontSize: 16, isBold: true),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
"Service Charges".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
"${scheduleData.amountTotal.toString()} SAR".toText(fontSize: 16, isBold: true),
LocaleKeys.serviceCharges.tr().toText(
fontSize: 14,
color: MyColors.lightTextColor,
isBold: true),
"${scheduleData.amountTotal.toString()} SAR"
.toText(fontSize: 16, isBold: true),
],
),
if (scheduleData.appointmentType == 1) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
"Location Charges ($rangePricePerKm x $totalKms )".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
"${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true),
(LocaleKeys.locationCharges.tr() +
" ($rangePricePerKm x $totalKms )")
.toText(
fontSize: 14,
color: MyColors.lightTextColor,
isBold: true),
("${totalServicePrice.toString()} " +
LocaleKeys.sar.tr())
.toText(fontSize: 16, isBold: true),
],
),
],
@ -198,12 +258,16 @@ class ReviewAppointment extends StatelessWidget {
],
);
},
separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
separatorBuilder: (BuildContext context, int index) =>
Divider(thickness: 2),
).paddingOnly(bottom: 10),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0));
).toWhiteContainer(
width: double.infinity,
allPading: 12,
margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0));
},
);
}
@ -221,13 +285,21 @@ class ReviewAppointment extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Payable now".toText(fontSize: 14, isBold: true),
LocaleKeys.payableNow.tr().toText(fontSize: 14, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.amountToPayForAppointment.toString().toText(fontSize: 16, isBold: true),
appointmentsVM.amountToPayForAppointment
.toString()
.toText(fontSize: 16, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
LocaleKeys.sar
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 12,
isBold: true)
.paddingOnly(bottom: 2),
],
)
],
@ -235,13 +307,24 @@ class ReviewAppointment extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Remaining Amount".toText(fontSize: 14, isBold: true),
LocaleKeys.remainingAmount
.tr()
.toText(fontSize: 14, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(appointmentsVM.totalAmount - appointmentsVM.amountToPayForAppointment).toString().toText(fontSize: 16, isBold: true),
(appointmentsVM.totalAmount -
appointmentsVM.amountToPayForAppointment)
.toString()
.toText(fontSize: 16, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
LocaleKeys.sar
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 12,
isBold: true)
.paddingOnly(bottom: 2),
],
)
],
@ -250,13 +333,21 @@ class ReviewAppointment extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total Amount ".toText(fontSize: 18, isBold: true),
LocaleKeys.totalAmount.tr().toText(fontSize: 18, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.totalAmount.toString().toText(fontSize: 29, isBold: true),
appointmentsVM.totalAmount
.toString()
.toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
LocaleKeys.sar
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 16,
isBold: true)
.paddingOnly(bottom: 5),
],
)
],
@ -267,7 +358,7 @@ class ReviewAppointment extends StatelessWidget {
child: ShowFillButton(
maxHeight: 55,
backgroundColor: MyColors.darkPrimaryColor,
title: "Book Appointment",
title: LocaleKeys.bookAppointment.tr(),
onPressed: () {
appointmentsVM.onBookAppointmentPressed(context);
},
@ -282,7 +373,7 @@ class ReviewAppointment extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Review Appointment",
title: LocaleKeys.reviewAppointment.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),

@ -4,6 +4,7 @@ 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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
@ -15,6 +16,7 @@ import 'package:mc_common_app/widgets/common_widgets/slider_widget.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class BranchesFilterView extends StatefulWidget {
const BranchesFilterView({super.key});
@ -45,7 +47,7 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Branches Filter",
title: LocaleKeys.branchesFilter.tr(),
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
@ -55,7 +57,8 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
},
),
body: Consumer<AppointmentsVM>(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
builder: (BuildContext context, AppointmentsVM appointmentsVM,
Widget? child) {
return WillPopScope(
onWillPop: () async {
context.read<AdVM>().resetValues();
@ -67,31 +70,55 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
children: [
20.height,
SearchEntityWidget(
title: "Search By Provider",
title: LocaleKeys.searchByProvider.tr(),
actionWidget: Builder(
builder: (context) {
return DropdownField(
(DropValue value) => appointmentsVM.updateBranchFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
(DropValue value) => appointmentsVM
.updateBranchFilterSelectedProviderId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value),
isForSearch: true),
list: appointmentsVM.providersDropList,
dropdownValue: appointmentsVM.branchFilterSelectedProviderId.selectedId != -1
? DropValue(appointmentsVM.branchFilterSelectedProviderId.selectedId, appointmentsVM.branchFilterSelectedProviderId.selectedOption, "")
dropdownValue: appointmentsVM
.branchFilterSelectedProviderId
.selectedId !=
-1
? DropValue(
appointmentsVM
.branchFilterSelectedProviderId
.selectedId,
appointmentsVM
.branchFilterSelectedProviderId
.selectedOption,
"")
: null,
hint: "Select Provider",
hint: LocaleKeys.selectProvider.tr(),
);
},
),
historyContent: appointmentsVM.branchFilterProviderSearchHistory,
historyContent:
appointmentsVM.branchFilterProviderSearchHistory,
onHistoryItemDeleted: (index) {
appointmentsVM.removeBranchFilterProviderSearchHistory(index: index);
appointmentsVM.removeBranchFilterProviderSearchHistory(
index: index);
},
onHistoryItemTapped: (DropValue value) =>
appointmentsVM.updateBranchFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
appointmentsVM.updateBranchFilterSelectedProviderId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value),
isForSearch: true),
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
const Divider(thickness: 1.2)
.paddingOnly(top: 5, bottom: 5),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Search By Distance".toText(fontSize: 16, isBold: true),
LocaleKeys.searchByDistance
.tr()
.toText(fontSize: 16, isBold: true),
Row(
children: [
"0 KM".toText(fontSize: 12, isBold: true),
@ -99,59 +126,104 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
child: SliderWidget(
minValue: 0,
maxValue: 100,
value: appointmentsVM.branchFilterCurrentDistance,
onChanged: appointmentsVM.updateBranchFilterCurrentDistance,
value:
appointmentsVM.branchFilterCurrentDistance,
onChanged: appointmentsVM
.updateBranchFilterCurrentDistance,
),
),
"${appointmentsVM.branchFilterCurrentDistance.toInt()} KM".toText(fontSize: 12, isBold: true),
"${appointmentsVM.branchFilterCurrentDistance.toInt()} KM"
.toText(fontSize: 12, isBold: true),
],
),
],
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
const Divider(thickness: 1.2)
.paddingOnly(top: 5, bottom: 5),
SearchEntityWidget(
title: "Search By Category",
title: LocaleKeys.searchByCategory.tr(),
actionWidget: Builder(
builder: (context) {
return DropdownField(
(DropValue value) => appointmentsVM.updateBranchFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
(DropValue value) => appointmentsVM
.updateBranchFilterSelectedCategoryId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value),
isForSearch: true),
list: appointmentsVM.categoryDropList,
dropdownValue: appointmentsVM.branchFilterSelectedCategoryId.selectedId != -1
? DropValue(appointmentsVM.branchFilterSelectedCategoryId.selectedId, appointmentsVM.branchFilterSelectedCategoryId.selectedOption, "")
dropdownValue: appointmentsVM
.branchFilterSelectedCategoryId
.selectedId !=
-1
? DropValue(
appointmentsVM
.branchFilterSelectedCategoryId
.selectedId,
appointmentsVM
.branchFilterSelectedCategoryId
.selectedOption,
"")
: null,
hint: "Select Category",
hint: LocaleKeys.selectCategory.tr(),
);
},
),
historyContent: appointmentsVM.branchFilterCategorySearchHistory,
historyContent:
appointmentsVM.branchFilterCategorySearchHistory,
onHistoryItemDeleted: (index) {
appointmentsVM.removeBranchFilterCategorySearchHistory(index: index);
appointmentsVM.removeBranchFilterCategorySearchHistory(
index: index);
},
onHistoryItemTapped: (DropValue value) =>
appointmentsVM.updateBranchFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
appointmentsVM.updateBranchFilterSelectedCategoryId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value),
isForSearch: true),
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
const Divider(thickness: 1.2)
.paddingOnly(top: 5, bottom: 5),
SearchEntityWidget(
title: "Search By Service",
title: LocaleKeys.searchByService.tr(),
actionWidget: Builder(builder: (context) {
return DropdownField(
(DropValue value) => appointmentsVM.updateBranchFilterSelectedServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
(DropValue value) => appointmentsVM
.updateBranchFilterSelectedServiceId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value),
isForSearch: true),
list: appointmentsVM.servicesDropList,
dropdownValue: appointmentsVM.branchFilterSelectedServiceId.selectedId != -1
? DropValue(appointmentsVM.branchFilterSelectedServiceId.selectedId, appointmentsVM.branchFilterSelectedServiceId.selectedOption, "")
dropdownValue: appointmentsVM
.branchFilterSelectedServiceId
.selectedId !=
-1
? DropValue(
appointmentsVM
.branchFilterSelectedServiceId.selectedId,
appointmentsVM.branchFilterSelectedServiceId
.selectedOption,
"")
: null,
hint: "Select Services",
hint: LocaleKeys.selectService.tr(),
);
}),
historyContent: appointmentsVM.branchFilterServicesSearchHistory,
onHistoryItemDeleted: (index) => appointmentsVM.removeBranchFilterServicesSearchHistory(index: index),
historyContent:
appointmentsVM.branchFilterServicesSearchHistory,
onHistoryItemDeleted: (index) => appointmentsVM
.removeBranchFilterServicesSearchHistory(
index: index),
onHistoryItemTapped: (DropValue value) => null,
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
const Divider(thickness: 1.2)
.paddingOnly(top: 5, bottom: 5),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Search By Minimum Ratings".toText(fontSize: 16, isBold: true),
LocaleKeys.searchByMinimumRatings
.tr()
.toText(fontSize: 16, isBold: true),
Row(
children: [
"1 Star".toText(fontSize: 12, isBold: true),
@ -160,10 +232,12 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
minValue: 0,
maxValue: 5,
value: appointmentsVM.branchFilterByRating,
onChanged: appointmentsVM.updateBranchFilterByRating,
onChanged:
appointmentsVM.updateBranchFilterByRating,
),
),
"${appointmentsVM.branchFilterByRating.toInt()} Star".toText(fontSize: 12, isBold: true),
"${appointmentsVM.branchFilterByRating.toInt()} Star"
.toText(fontSize: 12, isBold: true),
],
),
],
@ -180,7 +254,7 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Search",
title: LocaleKeys.search.tr(),
onPressed: () {
Navigator.pop(context);
appointmentsVM.getBranchesBasedOnFilters();
@ -195,11 +269,11 @@ class _BranchesFilterViewState extends State<BranchesFilterView> {
8.height,
InkWell(
onTap: () => appointmentsVM.clearBranchFilters(),
child: "Clear Filters".toText(
fontSize: 14,
isBold: true,
color: MyColors.darkPrimaryColor,
),
child: LocaleKeys.clearFilters.tr().toText(
fontSize: 14,
isBold: true,
color: MyColors.darkPrimaryColor,
),
),
10.height,
],

@ -6,6 +6,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -19,6 +20,7 @@ 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' as lcl;
class ChatView extends StatelessWidget {
final ChatViewArguments chatViewArguments;
@ -32,11 +34,15 @@ class ChatView extends StatelessWidget {
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Consumer(builder:
(BuildContext context, RequestsVM requestsVM, Widget? child) {
return InfoBottomSheet(
title: "Make an offer".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
title: LocaleKeys.makeAnOffer
.tr()
.toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -48,7 +54,7 @@ class ChatView extends StatelessWidget {
value: requestsVM.offerPrice,
errorValue: requestsVM.offerPriceError,
keyboardType: TextInputType.number,
hint: "Enter amount",
hint: LocaleKeys.enterAmount.tr(),
onChanged: (v) => requestsVM.updateOfferPrice(v),
),
12.height,
@ -57,14 +63,15 @@ class ChatView extends StatelessWidget {
value: requestsVM.offerDescription,
errorValue: requestsVM.offerDescriptionError,
keyboardType: TextInputType.text,
hint: "Description",
onChanged: (v) => requestsVM.updateOfferDescription(v),
hint: LocaleKeys.description.tr(),
onChanged: (v) =>
requestsVM.updateOfferDescription(v),
),
],
),
25.height,
ShowFillButton(
title: "Submit",
title: LocaleKeys.submit.tr(),
onPressed: () {
requestsVM.onSendOfferPressed(
context: context,
@ -91,22 +98,30 @@ class ChatView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: "Chat"),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
appBar: CustomAppBar(title: LocaleKeys.chat.tr()),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context,
ChatVM chatVM, RequestsVM requestVM, Widget? child) {
final chatMessages = AppState().currentAppType == AppType.customer
? chatVM.serviceProviderOffersList[chatViewArguments.providerIndex].chatMessages
: requestVM.myFilteredRequests[chatViewArguments.requestIndex].chatMessages;
? chatVM.serviceProviderOffersList[chatViewArguments.providerIndex]
.chatMessages
: requestVM.myFilteredRequests[chatViewArguments.requestIndex]
.chatMessages;
return chatMessages == null
? Center(child: "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor))
? Center(
child: LocaleKeys.noRequestsShow
.tr()
.toText(fontSize: 16, color: MyColors.lightTextColor))
: Column(
children: [
Expanded(
child: ListView.separated(
itemCount: chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height,
separatorBuilder: (BuildContext context, int index) =>
20.height,
itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatMessages[index];
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel);
return ChatMessageCustomWidget(
chatMessageModel: chatMessageModel);
},
).horPaddingMain(),
),
@ -132,7 +147,7 @@ class ChatView extends StatelessWidget {
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: "Type your message here..",
hint: LocaleKeys.typeMessageHere.tr(),
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
@ -178,7 +193,8 @@ class ChatMessageCustomWidget extends StatefulWidget {
const ChatMessageCustomWidget({super.key, required this.chatMessageModel});
@override
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
State<ChatMessageCustomWidget> createState() =>
_ChatMessageCustomWidgetState();
}
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
@ -188,11 +204,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return Consumer(
builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return InfoBottomSheet(
title: "Make an offer".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
title: LocaleKeys.makeAnOffer
.tr()
.toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -203,14 +223,18 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
ListView.separated(
shrinkWrap: true,
itemCount: chatVM.offerRejectModelList.length,
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 0.5),
separatorBuilder: (BuildContext context, int index) =>
const Divider(thickness: 0.5),
itemBuilder: (BuildContext context, int index) {
OfferRequestCommentModel offerRequestCommentModel = chatVM.offerRejectModelList[index];
OfferRequestCommentModel offerRequestCommentModel =
chatVM.offerRejectModelList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
isChecked:
offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
chatVM.updateSelectionInOfferRejectModelList(index);
chatVM.updateSelectionInOfferRejectModelList(
index);
},
selectedColor: MyColors.darkPrimaryColor,
);
@ -222,14 +246,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
value: chatVM.rejectOfferDescription,
errorValue: chatVM.rejectOfferDescriptionError,
keyboardType: TextInputType.text,
hint: "Description",
onChanged: (v) => chatVM.updateRejectOfferDescription(v),
hint: LocaleKeys.description.tr(),
onChanged: (v) =>
chatVM.updateRejectOfferDescription(v),
),
],
),
25.height,
ShowFillButton(
title: "Submit",
title: LocaleKeys.submit.tr(),
onPressed: () {},
maxWidth: double.infinity,
),
@ -242,8 +267,12 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
);
}
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) {
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
Widget buildOfferDetailsInChatMessage(
{required ChatMessageModel chatMessageModel,
required BuildContext context}) {
final requestOfferStatusEnum =
chatMessageModel.reqOffer!.requestOfferStatusEnum ??
RequestOfferStatusEnum.offer;
switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer:
@ -253,9 +282,18 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${chatMessageModel.reqOffer!.price}".toText(fontSize: 19, isBold: true, color: AppState().currentAppType == AppType.provider ? MyColors.white : MyColors.darkTextColor),
"${chatMessageModel.reqOffer!.price}".toText(
fontSize: 19,
isBold: true,
color: AppState().currentAppType == AppType.provider
? MyColors.white
: MyColors.darkTextColor),
5.width,
"SAR".toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
LocaleKeys.sar.tr().toText(
color: MyColors.lightTextColor,
height: 2.2,
fontSize: 10,
isBold: true),
],
),
if (widget.chatMessageModel.isMyMessage == false) ...[
@ -265,21 +303,24 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Accept",
title: LocaleKeys.accept.tr(),
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () async {
int status = await context.read<ChatVM>().onActionOfferTapped(
context: context,
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
reqOfferId: chatMessageModel.reqOfferID ?? -1,
);
int status =
await context.read<ChatVM>().onActionOfferTapped(
context: context,
requestOfferStatusEnum:
RequestOfferStatusEnum.accepted,
reqOfferId: chatMessageModel.reqOfferID ?? -1,
);
if (status != -1) {
log("accepted: $status");
if (chatMessageModel.reqOfferID == status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
chatMessageModel.reqOffer!.requestOfferStatusEnum =
RequestOfferStatusEnum.accepted;
setState(() {});
}
}
@ -292,7 +333,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Reject",
title: LocaleKeys.reject.tr(),
borderColor: MyColors.redColor,
isFilled: false,
backgroundColor: MyColors.white,
@ -312,48 +353,64 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return Column(
children: [
Center(
child: "New Offer Required.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
child: LocaleKeys.newOfferRequired.tr().toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(
borderRadius: 40,
width: double.infinity,
backgroundColor:
MyColors.adPendingStatusColor.withOpacity(0.16)),
],
);
case RequestOfferStatusEnum.accepted:
return Column(
children: [
Center(
child: "Offer has been accepted.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
child: LocaleKeys.offerHasBeenAccepted.tr().toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(
borderRadius: 40,
width: double.infinity,
backgroundColor:
MyColors.adPendingStatusColor.withOpacity(0.16)),
],
);
case RequestOfferStatusEnum.rejected:
return Column(
children: [
Center(
child: "Offer has been rejected.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
child: LocaleKeys.offerHasBeenRejected.tr().toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(
borderRadius: 40,
width: double.infinity,
backgroundColor:
MyColors.adPendingStatusColor.withOpacity(0.16)),
],
);
case RequestOfferStatusEnum.cancel:
return Column(
children: [
Center(
child: "Offer has been cancelled.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
child: LocaleKeys.offerHasBeenCancelled.tr().toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(
borderRadius: 40,
width: double.infinity,
backgroundColor:
MyColors.adPendingStatusColor.withOpacity(0.16)),
],
);
}
@ -362,7 +419,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: (widget.chatMessageModel.isMyMessage ?? false) ? TextDirection.rtl : TextDirection.ltr,
textDirection: (widget.chatMessageModel.isMyMessage ?? false)
? TextDirection.rtl
: TextDirection.ltr,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -384,7 +443,10 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
((widget.chatMessageModel.isMyMessage ?? false) ? "You" : widget.chatMessageModel.senderName ?? "").toText(fontSize: 16, isBold: true),
((widget.chatMessageModel.isMyMessage ?? false)
? "You"
: widget.chatMessageModel.senderName ?? "")
.toText(fontSize: 16, isBold: true),
],
),
5.height,
@ -396,8 +458,12 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Expanded(
child: Directionality(
textDirection: TextDirection.ltr,
child: (widget.chatMessageModel.chatText ?? "").toText(
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
child:
(widget.chatMessageModel.chatText ?? "").toText(
color:
(widget.chatMessageModel.isMyMessage ?? false)
? MyColors.white
: MyColors.lightTextColor,
fontSize: 12,
// isBold: true,
@ -406,15 +472,26 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
),
],
),
if (widget.chatMessageModel.chatMessageTypeEnum == ChatMessageTypeEnum.offer) ...[
buildOfferDetailsInChatMessage(chatMessageModel: widget.chatMessageModel, context: context),
if (widget.chatMessageModel.chatMessageTypeEnum ==
ChatMessageTypeEnum.offer) ...[
buildOfferDetailsInChatMessage(
chatMessageModel: widget.chatMessageModel,
context: context),
],
],
).toContainer(
isShadowEnabled: !(widget.chatMessageModel.isMyMessage ?? false),
backgroundColor: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.darkIconColor : MyColors.white,
isShadowEnabled:
!(widget.chatMessageModel.isMyMessage ?? false),
backgroundColor:
(widget.chatMessageModel.isMyMessage ?? false)
? MyColors.darkIconColor
: MyColors.white,
borderRadius: 0,
margin: EdgeInsets.fromLTRB((widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0, !(widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0),
margin: EdgeInsets.fromLTRB(
(widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0,
0,
!(widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0,
0),
),
],
),

@ -2,6 +2,7 @@ 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/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/utils.dart';
@ -9,6 +10,7 @@ import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class PaymentMethodsView extends StatelessWidget {
final PaymentTypes paymentType;
@ -22,7 +24,7 @@ class PaymentMethodsView extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Payment Method",
title: LocaleKeys.paymentMethod.tr(),
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
@ -34,33 +36,46 @@ class PaymentMethodsView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
20.height,
"Select Payment Method".toText(fontSize: 18, isBold: true),
LocaleKeys.selectPaymentMethod
.tr()
.toText(fontSize: 18, isBold: true),
15.height,
Consumer(
builder: (BuildContext context, PaymentVM paymentVm, Widget? child) {
builder:
(BuildContext context, PaymentVM paymentVm, Widget? child) {
return Expanded(
child: ListView(
shrinkWrap: true,
children: [
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.mada,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.mada),
isSelected: paymentVm.selectedPaymentMethod ==
PaymentMethods.mada,
onTap: () => paymentVm
.updateSelectedPaymentMethod(PaymentMethods.mada),
cardAsset: MyAssets.madaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.visa,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.visa),
isSelected: paymentVm.selectedPaymentMethod ==
PaymentMethods.visa,
onTap: () => paymentVm
.updateSelectedPaymentMethod(PaymentMethods.visa),
cardAsset: MyAssets.visaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.applePay,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.applePay),
isSelected: paymentVm.selectedPaymentMethod ==
PaymentMethods.applePay,
onTap: () => paymentVm.updateSelectedPaymentMethod(
PaymentMethods.applePay),
cardAsset: MyAssets.applePayPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.masterCard,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.masterCard),
isSelected: paymentVm.selectedPaymentMethod ==
PaymentMethods.masterCard,
onTap: () => paymentVm.updateSelectedPaymentMethod(
PaymentMethods.masterCard),
cardAsset: MyAssets.mastercardPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.tamara,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.tamara),
isSelected: paymentVm.selectedPaymentMethod ==
PaymentMethods.tamara,
onTap: () => paymentVm.updateSelectedPaymentMethod(
PaymentMethods.tamara),
cardAsset: MyAssets.tamaraEngPng),
],
),
@ -71,7 +86,7 @@ class PaymentMethodsView extends StatelessWidget {
width: double.infinity,
child: ShowFillButton(
maxHeight: 55,
title: "Continue",
title: LocaleKeys.continu.tr(),
onPressed: () async {
bool isNeedToCallPayment = true;
if (onTempContinue != null) {
@ -99,7 +114,12 @@ class PaymentMethodContainer extends StatelessWidget {
final String cardAsset;
final Function() onTap;
const PaymentMethodContainer({Key? key, required this.isSelected, required this.cardAsset, required this.onTap}) : super(key: key);
const PaymentMethodContainer(
{Key? key,
required this.isSelected,
required this.cardAsset,
required this.onTap})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -112,7 +132,9 @@ class PaymentMethodContainer extends StatelessWidget {
decoration: BoxDecoration(
color: MyColors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isSelected ? Colors.green : Colors.transparent, width: isSelected ? 2.0 : 0.0),
border: Border.all(
color: isSelected ? Colors.green : Colors.transparent,
width: isSelected ? 2.0 : 0.0),
),
child: Padding(
padding: const EdgeInsets.all(12),
@ -121,7 +143,11 @@ class PaymentMethodContainer extends StatelessWidget {
Container(
width: 24,
height: 24,
decoration: Utils.containerColorRadiusBorderWidth(isSelected ? MyColors.primaryColor : Colors.transparent, 100, Colors.grey, 0.5),
decoration: Utils.containerColorRadiusBorderWidth(
isSelected ? MyColors.primaryColor : Colors.transparent,
100,
Colors.grey,
0.5),
),
12.width,
Container(
@ -131,7 +157,12 @@ class PaymentMethodContainer extends StatelessWidget {
child: Image.asset(cardAsset),
),
Utils.mFlex(1),
isSelected ? Utils.statusContainerChip(text: "Selected", padding: EdgeInsets.symmetric(vertical: 6, horizontal: 10)) : SizedBox(),
isSelected
? Utils.statusContainerChip(
text: "Selected",
padding:
EdgeInsets.symmetric(vertical: 6, horizontal: 10))
: SizedBox(),
],
),
),

@ -9,6 +9,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/app_permission_handler.dart';
import 'package:mc_common_app/view_models/service_view_model.dart';
@ -19,6 +20,7 @@ import 'package:mc_common_app/views/user/change_password_page.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class ProfileScreen extends StatefulWidget {
const ProfileScreen({Key? key}) : super(key: key);
@ -52,15 +54,29 @@ class _ProfileScreenState extends State<ProfileScreen> {
flex: 3,
child: Container(
decoration: BoxDecoration(
image: AppState().getUser.data!.userInfo!.userLocalImage != null
image: AppState()
.getUser
.data!
.userInfo!
.userLocalImage !=
null
? DecorationImage(
image: FileImage(AppState().getUser.data!.userInfo!.userLocalImage!),
image: FileImage(AppState()
.getUser
.data!
.userInfo!
.userLocalImage!),
fit: BoxFit.cover,
)
: AppState().getUser.data!.userInfo!.userImageUrl != null
: AppState().getUser.data!.userInfo!.userImageUrl !=
null
? DecorationImage(
image: CachedNetworkImageProvider(
AppState().getUser.data!.userInfo!.userImageUrl,
AppState()
.getUser
.data!
.userInfo!
.userImageUrl,
),
fit: BoxFit.cover,
)
@ -87,40 +103,52 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: ListView(
children: [
20.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(
children: [
CustomProfileOptionsTile(
titleText: "Country",
titleText: LocaleKeys.country.tr(),
subtitleText: "Saudi Arabia",
needBorderBelow: true,
onTap: () {},
),
CustomProfileOptionsTile(
titleText: "Email",
subtitleText: "${AppState().getUser.data!.userInfo!.email}",
titleText: LocaleKeys.email.tr(),
subtitleText:
"${AppState().getUser.data!.userInfo!.email}",
needBorderBelow: true,
onTap: () {
Navigator.pushNamed(context, AppRoutes.changeEmailPage);
Navigator.pushNamed(
context, AppRoutes.changeEmailPage);
},
),
CustomProfileOptionsTile(
titleText: "Phone Number",
subtitleText: "${AppState().getUser.data!.userInfo!.email}",
titleText: LocaleKeys.phoneNumber.tr(),
subtitleText:
"${AppState().getUser.data!.userInfo!.email}",
needBorderBelow: true,
onTap: () {
Navigator.pushNamed(context, AppRoutes.changeMobilePage);
Navigator.pushNamed(
context, AppRoutes.changeMobilePage);
},
),
CustomProfileOptionsTile(
titleText: "Password",
titleText: LocaleKeys.password.tr(),
subtitleText: "************",
onTap: () {
Navigator.pushNamed(context, AppRoutes.changePassword);
Navigator.pushNamed(
context, AppRoutes.changePassword);
},
),
],
).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 20, 24, 0), borderRadius: 0),
).toContainer(
width: double.infinity,
isShadowEnabled: true,
paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 20, 24, 0),
borderRadius: 0),
],
),
),
@ -133,7 +161,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
height: 90,
alignment: Alignment.centerLeft,
child: ClipOval(
child: AppState().getUser.data!.userInfo!.userLocalImage != null
child: AppState().getUser.data!.userInfo!.userLocalImage !=
null
? Image.file(
AppState().getUser.data!.userInfo!.userLocalImage!,
width: 90,
@ -141,7 +170,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
fit: BoxFit.fill,
)
: CachedNetworkImage(
imageUrl: "${AppState().getUser.data!.userInfo!.userImageUrl}",
imageUrl:
"${AppState().getUser.data!.userInfo!.userImageUrl}",
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
@ -150,8 +180,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
),
),
placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) => const Icon(Icons.error),
placeholder: (context, url) =>
const Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
const Icon(Icons.error),
width: 90,
height: 90,
fit: BoxFit.fill,
@ -168,8 +200,14 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: Container(
height: 35,
width: 35,
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),
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),
).onPress(
() async {
model.updateUserImage(context);

@ -1,3 +1,4 @@
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
@ -13,6 +14,7 @@ import 'package:mc_common_app/widgets/dropdown/dropdow_field.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 CreateRequestPage extends StatelessWidget {
const CreateRequestPage({super.key});
@ -20,8 +22,8 @@ class CreateRequestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(
title: "Create Request",
appBar: CustomAppBar(
title: LocaleKeys.createRequest.tr(),
),
body: Consumer<RequestsVM>(builder: (context, requestsVM, widget) {
return Column(
@ -31,204 +33,323 @@ class CreateRequestPage extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Detail".toText(fontSize: 18, isBold: true),
LocaleKeys.vehicleDetails
.tr()
.toText(fontSize: 18, isBold: true),
8.height,
if (requestsVM.isFetchingRequestType) ...[
const Center(
child: CircularProgressIndicator(),
),
] else
...[
Builder(builder: (context) {
List<DropValue> requestTypeDrop = [];
for (var element in requestsVM.myRequestsTypeEnum) {
requestTypeDrop.add(DropValue(element.enumValue.toInt() ?? 0, element.enumValueStr ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionRequestTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: requestTypeDrop,
dropdownValue: requestsVM.requestTypeId.selectedId != -1 ? DropValue(requestsVM.requestTypeId.selectedId, requestsVM.requestTypeId.selectedOption, "") : null,
hint: "Request Type",
errorValue: requestsVM.requestTypeId.errorValue,
);
}),
],
] else ...[
Builder(builder: (context) {
List<DropValue> requestTypeDrop = [];
for (var element in requestsVM.myRequestsTypeEnum) {
requestTypeDrop.add(DropValue(
element.enumValue.toInt() ?? 0,
element.enumValueStr ?? "",
""));
}
return DropdownField(
(DropValue value) => requestsVM
.updateSelectionRequestTypeId(SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: requestTypeDrop,
dropdownValue:
requestsVM.requestTypeId.selectedId != -1
? DropValue(
requestsVM.requestTypeId.selectedId,
requestsVM.requestTypeId.selectedOption,
"")
: null,
hint: LocaleKeys.requestType.tr(),
errorValue: requestsVM.requestTypeId.errorValue,
);
}),
],
8.height,
if (requestsVM.requestTypeId.selectedId != -1)
if (requestsVM.isFetchingVehicleType) ...[
const Center(
child: CircularProgressIndicator(),
),
] else
...[
Builder(builder: (context) {
List<DropValue> vehicleTypeDrop = [];
for (var element in requestsVM.vehicleTypes) {
vehicleTypeDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTypeDrop,
dropdownValue: requestsVM.vehicleTypeId.selectedId != -1 ? DropValue(requestsVM.vehicleTypeId.selectedId, requestsVM.vehicleTypeId.selectedOption, "") : null,
hint: "Vehicle Type",
errorValue: requestsVM.vehicleTypeId.errorValue,
);
}),
],
] else ...[
Builder(builder: (context) {
List<DropValue> vehicleTypeDrop = [];
for (var element in requestsVM.vehicleTypes) {
vehicleTypeDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.vehicleTypeName ?? "",
""));
}
return DropdownField(
(DropValue value) => requestsVM
.updateSelectionVehicleTypeId(SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: vehicleTypeDrop,
dropdownValue:
requestsVM.vehicleTypeId.selectedId != -1
? DropValue(
requestsVM.vehicleTypeId.selectedId,
requestsVM.vehicleTypeId.selectedOption,
"")
: null,
hint: LocaleKeys.vehicleType.tr(),
errorValue: requestsVM.vehicleTypeId.errorValue,
);
}),
],
8.height,
if (requestsVM.vehicleTypeId.selectedId != -1)
if (requestsVM.isFetchingVehicleDetail) ...[
const Center(
child: CircularProgressIndicator(),
),
] else
...[
Column(
children: [
Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in requestsVM.vehicleBrands) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleBrandsDrop,
dropdownValue: requestsVM.vehicleBrandId.selectedId != -1 ? DropValue(requestsVM.vehicleBrandId.selectedId, requestsVM.vehicleBrandId.selectedOption, "") : null,
hint: "Brand",
errorValue: requestsVM.vehicleBrandId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in requestsVM.vehicleModels) {
if (requestsVM.vehicleBrandId.selectedId == element.vehicleBrandID) vehicleModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.model ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue: requestsVM.vehicleModelId.selectedId != -1 ? DropValue(requestsVM.vehicleModelId.selectedId, requestsVM.vehicleModelId.selectedOption, "") : null,
hint: "Model",
errorValue: requestsVM.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element in requestsVM.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
] else ...[
Column(
children: [
Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in requestsVM.vehicleBrands) {
vehicleBrandsDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.vehicleBrandDescription ?? "",
""));
}
return DropdownField(
(DropValue value) =>
requestsVM.updateSelectionVehicleBrandId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: vehicleBrandsDrop,
dropdownValue:
requestsVM.vehicleBrandId.selectedId != -1
? DropValue(
requestsVM
.vehicleBrandId.selectedId,
requestsVM
.vehicleBrandId.selectedOption,
"")
: null,
hint: LocaleKeys.brand.tr(),
errorValue:
requestsVM.vehicleBrandId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in requestsVM.vehicleModels) {
if (requestsVM.vehicleBrandId.selectedId ==
element.vehicleBrandID)
vehicleModelsDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.model ?? "",
""));
}
return DropdownField(
(DropValue value) =>
requestsVM.updateSelectionVehicleModelId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue:
requestsVM.vehicleModelId.selectedId != -1
? DropValue(
requestsVM
.vehicleModelId.selectedId,
requestsVM
.vehicleModelId.selectedOption,
"")
: null,
hint: LocaleKeys.model.tr(),
errorValue:
requestsVM.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element
in requestsVM.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.modelYear ?? "",
""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue:
requestsVM.vehicleModelYearId.selectedId != -1 ? DropValue(requestsVM.vehicleModelYearId.selectedId, requestsVM.vehicleModelYearId.selectedOption, "") : null,
hint: "Year",
errorValue: requestsVM.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in requestsVM.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.countryName ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue: requestsVM.vehicleCountryId.selectedId != -1
? DropValue(requestsVM.vehicleCountryId.selectedId, requestsVM.vehicleCountryId.selectedOption, "")
: null,
hint: "Country",
errorValue: requestsVM.vehicleCountryId.errorValue,
);
}),
if (requestsVM.vehicleCountryId.selectedId != -1) ...[
if (requestsVM.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
),
] else
...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element in requestsVM.vehicleCities) {
vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: requestsVM.vehicleCityId.selectedId != -1 ? DropValue(requestsVM.vehicleCityId.selectedId, requestsVM.vehicleCityId.selectedOption, "") : null,
hint: "City",
errorValue: requestsVM.vehicleCityId.errorValue,
);
}),
],
],
8.height,
TxtField(
hint: "Price",
value: requestsVM.price,
keyboardType: TextInputType.number,
onChanged: (e) => requestsVM.updatePrice(e),
),
8.height,
TxtField(
hint: "Description",
maxLines: 5,
value: requestsVM.description,
onChanged: (e) => requestsVM.updateDescription(e),
),
8.height,
DottedRectContainer(
onTap: () => context.read<RequestsVM>().pickMultipleImages(),
text: "Attach Image",
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (requestsVM.vehicleImageError != "") ...[
10.height,
return DropdownField(
(DropValue value) => requestsVM
.updateSelectionVehicleModelYearId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue:
requestsVM.vehicleModelYearId.selectedId !=
-1
? DropValue(
requestsVM
.vehicleModelYearId.selectedId,
requestsVM.vehicleModelYearId
.selectedOption,
"")
: null,
hint: LocaleKeys.year.tr(),
errorValue:
requestsVM.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in requestsVM.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.countryName ?? "",
""));
}
return DropdownField(
(DropValue value) =>
requestsVM.updateSelectionVehicleCountryId(
SelectionModel(
selectedOption: value.value,
selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue:
requestsVM.vehicleCountryId.selectedId != -1
? DropValue(
requestsVM
.vehicleCountryId.selectedId,
requestsVM.vehicleCountryId
.selectedOption,
"")
: null,
hint: LocaleKeys.country.tr(),
errorValue:
requestsVM.vehicleCountryId.errorValue,
);
}),
if (requestsVM.vehicleCountryId.selectedId !=
-1) ...[
if (requestsVM.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
requestsVM.vehicleImageError.toText(fontSize: 14, color: Colors.red),
const CircularProgressIndicator()
.paddingAll(10)
],
).paddingOnly(right: 10)
],
if (requestsVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedFilesContainer(
pickedFiles: requestsVM.pickedVehicleImages,
onCrossPressedPrimary: requestsVM.removeImageFromList,
onAddFilePressed: () {
context.read<RequestsVM>().pickMultipleImages();
},
),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element
in requestsVM.vehicleCities) {
vehicleCitiesDrop.add(DropValue(
element.id?.toInt() ?? 0,
element.cityName ?? "",
""));
}
return DropdownField(
(DropValue value) =>
requestsVM.updateSelectionVehicleCityId(
SelectionModel(
selectedId: value.id,
selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: requestsVM
.vehicleCityId.selectedId !=
-1
? DropValue(
requestsVM.vehicleCityId.selectedId,
requestsVM
.vehicleCityId.selectedOption,
"")
: null,
hint: LocaleKeys.city.tr(),
errorValue:
requestsVM.vehicleCityId.errorValue,
);
}),
],
16.height,
],
8.height,
TxtField(
hint: LocaleKeys.price.tr(),
value: requestsVM.price,
keyboardType: TextInputType.number,
onChanged: (e) => requestsVM.updatePrice(e),
),
8.height,
TxtField(
hint: LocaleKeys.description.tr(),
maxLines: 5,
value: requestsVM.description,
onChanged: (e) => requestsVM.updateDescription(e),
),
8.height,
DottedRectContainer(
onTap: () => context
.read<RequestsVM>()
.pickMultipleImages(),
text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (requestsVM.vehicleImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Checkbox(
value: requestsVM.isShippingDeliveryEnabled,
onChanged: null,
),
"Shipping/Delivery".toText(color: MyColors.darkPrimaryColor, isBold: true, fontSize: 18)
requestsVM.vehicleImageError
.toText(fontSize: 14, color: Colors.red),
],
).onPress(() {
requestsVM.updateShippingDeliverEnabled(!requestsVM.isShippingDeliveryEnabled);
}),
).paddingOnly(right: 10)
],
),
]
if (requestsVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedFilesContainer(
pickedFiles: requestsVM.pickedVehicleImages,
onCrossPressedPrimary:
requestsVM.removeImageFromList,
onAddFilePressed: () {
context
.read<RequestsVM>()
.pickMultipleImages();
},
),
],
16.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: requestsVM.isShippingDeliveryEnabled,
onChanged: null,
),
LocaleKeys.shippingDelivery.tr().toText(
color: MyColors.darkPrimaryColor,
isBold: true,
fontSize: 18)
],
).onPress(() {
requestsVM.updateShippingDeliverEnabled(
!requestsVM.isShippingDeliveryEnabled);
}),
],
),
]
],
).toContainer(isShadowEnabled: true, marginAll: 16, paddingAll: 12),
).toContainer(
isShadowEnabled: true, marginAll: 16, paddingAll: 12),
),
),
ShowFillButton(
title: "Create Request",
title: LocaleKeys.createRequest.tr(),
maxWidth: double.infinity,
margin: const EdgeInsets.all(16),
onPressed: () async {

@ -5,6 +5,7 @@ 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';
@ -13,6 +14,7 @@ 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 OfferListPage extends StatelessWidget {
final OfferListPageArguments offerListPageArguments;
@ -21,23 +23,29 @@ class OfferListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final List<ServiceProvidersOffers> serviceProviderOffers = offerListPageArguments.serviceProviderOffers;
final List<ServiceProvidersOffers> serviceProviderOffers =
offerListPageArguments.serviceProviderOffers;
return Scaffold(
appBar: const CustomAppBar(title: "Offers"),
appBar: CustomAppBar(title: LocaleKeys.offers.tr()),
body: serviceProviderOffers.isEmpty
? Center(child: "No Offers to show.".toText(fontSize: 16, color: MyColors.lightTextColor))
? 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];
ServiceProvidersOffers offersModel =
serviceProviderOffers[index];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(offersModel.name ?? "").toText(fontSize: 16, isBold: true),
(offersModel.name ?? "")
.toText(fontSize: 16, isBold: true),
Center(
child: "${offersModel.offerCount}".toText(
color: Colors.white,
@ -82,10 +90,12 @@ class OfferListPage extends StatelessWidget {
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.providerUserId}",
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
senderId:
AppState().getUser.data!.userInfo!.userId.toString(),
requestId: offerListPageArguments.requestId,
providerIndex: index,
requestIndex: -1, // This will be only send in case of provider
requestIndex:
-1, // This will be only send in case of provider
);
final chatVM = context.read<ChatVM>();
@ -99,7 +109,8 @@ class OfferListPage extends StatelessWidget {
providerOfferIndex: index,
)
.whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
() => navigateWithName(context, AppRoutes.chatView,
arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true);
},

@ -2,6 +2,7 @@
import 'dart:developer';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:flutter/material.dart';
@ -14,13 +15,18 @@ import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class RequestItem extends StatelessWidget {
final RequestModel request;
final AppType appType;
final int requestIndex;
const RequestItem({super.key, required this.request, required this.appType, required this.requestIndex});
const RequestItem(
{super.key,
required this.request,
required this.appType,
required this.requestIndex});
@override
Widget build(BuildContext context) {
@ -34,11 +40,16 @@ class RequestItem extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)),
Utils.statusContainerChip(
text: request.requestStatusName,
chipColor: Utils.getChipColorByRequestStatus(
request.requestStatus)),
6.height,
"${request.brand} ${request.model}".toText(fontSize: 16, isBold: true),
showItem("Model:", "${request.year}"),
showItem("Customer Name:", request.customerName),
"${request.brand} ${request.model}"
.toText(fontSize: 16, isBold: true),
showItem((LocaleKeys.model.tr()), "${request.year}"),
showItem(
(LocaleKeys.customerName.tr()), request.customerName),
],
),
),
@ -72,7 +83,7 @@ class RequestItem extends StatelessWidget {
)
],
),
showItem("Description: ", request.description),
showItem((LocaleKeys.description.tr()), request.description),
showItem("Price Range: ", ""),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -87,7 +98,8 @@ class RequestItem extends StatelessWidget {
isBold: true,
),
2.width,
"SAR"
LocaleKeys.sar
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 10,
@ -110,13 +122,20 @@ class RequestItem extends StatelessWidget {
return;
}
if (appType == AppType.provider) {
RequestDetailPageArguments requestDetailPageArguments = RequestDetailPageArguments(requestIndex: requestIndex, requestModel: request);
navigateWithName(context, AppRoutes.requestsDetailPage, arguments: requestDetailPageArguments);
RequestDetailPageArguments requestDetailPageArguments =
RequestDetailPageArguments(
requestIndex: requestIndex, requestModel: request);
navigateWithName(context, AppRoutes.requestsDetailPage,
arguments: requestDetailPageArguments);
} else {
ChatVM chatVM = context.read<ChatVM>();
await chatVM.getOffersFromProvidersByRequest(requestId: request.id, context: context);
OfferListPageArguments offerListPageArguments = OfferListPageArguments(serviceProviderOffers: chatVM.serviceProviderOffersList, requestId: request.id);
navigateWithName(context, AppRoutes.offersListPage, arguments: offerListPageArguments);
await chatVM.getOffersFromProvidersByRequest(
requestId: request.id, context: context);
OfferListPageArguments offerListPageArguments = OfferListPageArguments(
serviceProviderOffers: chatVM.serviceProviderOffersList,
requestId: request.id);
navigateWithName(context, AppRoutes.offersListPage,
arguments: offerListPageArguments);
}
});
}

@ -34,7 +34,8 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
// TODO: implement initState
super.initState();
branchVM = Provider.of<ServiceVM>(context, listen: false);
branchVM.getServiceProviderDocument(AppState().getUser.data!.userInfo!.providerId ?? 0);
branchVM.getServiceProviderDocument(
AppState().getUser.data!.userInfo!.providerId ?? 0);
}
@override
@ -73,7 +74,9 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
if (validation(model)) {
updateDocument(model);
} else {
Utils.showToast("All document's are mandatory for Dealership Provider");
Utils.showToast(LocaleKeys
.allDocumentMandatoryDealershipProvider
.tr());
}
} else {
updateDocument(model);
@ -102,7 +105,7 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
MResponse res = await model.updateDocument(model.document!.data);
Utils.hideLoading(context);
if (res.messageStatus == 1) {
Utils.showToast("Documents uploaded successfully");
Utils.showToast(LocaleKeys.documentsUploadedSuccessfully.tr());
} else {
Utils.showToast(res.message ?? "");
}
@ -111,7 +114,7 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
Widget showWidget(ServiceVM model) {
if (model.state == ViewState.idle) {
return model.document!.data!.isEmpty
? Text("LocaleKeys.somethingWrong.tr()")
? Text(LocaleKeys.somethingWrong.tr())
: ListView.separated(
itemBuilder: (context, index) {
return Column(
@ -124,19 +127,27 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 4, bottom: 8),
child: LocaleKeys.enter_licence_detail.tr().toText(fontSize: 14, color: MyColors.lightTextColor, textAlign: TextAlign.center),
padding: const EdgeInsets.only(
left: 20, right: 20, top: 4, bottom: 8),
child: LocaleKeys.enter_licence_detail.tr().toText(
fontSize: 14,
color: MyColors.lightTextColor,
textAlign: TextAlign.center),
),
TxtField(
hint: LocaleKeys.description.tr(),
maxLines: 3,
isBackgroundEnabled: true,
),
if ((model.document?.data![index].documentUrl ?? "").toString().isNotEmpty)
if ((model.document?.data![index].documentUrl ?? "")
.toString()
.isNotEmpty)
Column(
children: [
8.height,
(model.document?.data![index].documentUrl ?? "").toString().toText(
(model.document?.data![index].documentUrl ?? "")
.toString()
.toText(
fontSize: 14,
color: MyColors.lightTextColor,
),
@ -152,8 +163,10 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
height: 45,
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(color: MyColors.greyACColor, width: 2),
borderRadius: const BorderRadius.all(Radius.circular(0)),
border:
Border.all(color: MyColors.greyACColor, width: 2),
borderRadius:
const BorderRadius.all(Radius.circular(0)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,

@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/navigator.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';
class SettingOptionsHelp extends StatelessWidget {
const SettingOptionsHelp({super.key});
@ -13,7 +15,7 @@ class SettingOptionsHelp extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Help",
title: LocaleKeys.help.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
@ -27,23 +29,30 @@ class SettingOptionsHelp extends StatelessWidget {
children: [
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.info_rounded, size: 20),
titleText: "FAQs",
titleText: LocaleKeys.faqs.tr(),
needBorderBelow: true,
onTap: () {},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.mail, size: 20),
titleText: "Contact Us",
titleText: LocaleKeys.contactUs.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsFaqs),
onTap: () => navigateWithName(
context, AppRoutes.settingOptionsFaqs),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.lock, size: 20),
titleText: "Term & Privacy",
onTap: () => navigateWithName(context, AppRoutes.profileView),
titleText: LocaleKeys.termPrivacy.tr(),
onTap: () =>
navigateWithName(context, AppRoutes.profileView),
),
],
).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
).toContainer(
width: double.infinity,
isShadowEnabled: true,
paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0),
borderRadius: 0),
],
),
),
@ -60,7 +69,13 @@ class CustomSettingOptionsTile extends StatelessWidget {
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});
const CustomSettingOptionsTile(
{super.key,
required this.leadingWidget,
required this.onTap,
required this.titleText,
this.needBorderBelow = false,
this.isForLanguage = false});
@override
Widget build(BuildContext context) {
@ -76,7 +91,9 @@ class CustomSettingOptionsTile extends StatelessWidget {
titleText.toText(fontSize: 16),
],
),
isForLanguage ? const Icon(Icons.language, size: 18) : const Icon(Icons.arrow_forward, size: 18)
isForLanguage
? const Icon(Icons.language, size: 18)
: const Icon(Icons.arrow_forward, size: 18)
],
).onPress(onTap),
5.height,

@ -1,8 +1,10 @@
import 'package:flutter/material.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/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/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart';
class SettingOptionsFAQs extends StatelessWidget {
const SettingOptionsFAQs({super.key});
@ -11,7 +13,7 @@ class SettingOptionsFAQs extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "More",
title: LocaleKeys.more.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
@ -23,11 +25,27 @@ class SettingOptionsFAQs extends StatelessWidget {
children: [
Column(
children: [
CustomSettingOptionsTile(leadingWidget: const Icon(Icons.info, size: 20), titleText: "FAQs", needBorderBelow: true, onTap: () {}),
CustomSettingOptionsTile(leadingWidget: const Icon(Icons.mail, size: 20), titleText: "Contact Us", needBorderBelow: true, onTap: () {}),
CustomSettingOptionsTile(leadingWidget: const Icon(Icons.settings, size: 20), titleText: "Terms & Privacy", onTap: () {}),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.info, size: 20),
titleText: LocaleKeys.faqs.tr(),
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(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
).toContainer(
width: double.infinity,
isShadowEnabled: true,
paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0),
borderRadius: 0),
],
),
),

@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/navigator.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';
class SettingOptionsInviteFriends extends StatelessWidget {
const SettingOptionsInviteFriends({super.key});
@ -13,7 +15,7 @@ class SettingOptionsInviteFriends extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "More",
title: LocaleKeys.more.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
@ -27,23 +29,30 @@ class SettingOptionsInviteFriends extends StatelessWidget {
children: [
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20),
titleText: "Invite Friends",
titleText: LocaleKeys.inviteFriends.tr(),
needBorderBelow: true,
onTap: () {},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.help, size: 20),
titleText: "Help",
titleText: LocaleKeys.help.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsFaqs),
onTap: () => navigateWithName(
context, AppRoutes.settingOptionsFaqs),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20),
titleText: "Account",
onTap: () => navigateWithName(context, AppRoutes.profileView),
titleText: LocaleKeys.account.tr(),
onTap: () =>
navigateWithName(context, AppRoutes.profileView),
),
],
).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
).toContainer(
width: double.infinity,
isShadowEnabled: true,
paddingAll: 10,
margin: const EdgeInsets.fromLTRB(24, 24, 24, 0),
borderRadius: 0),
],
),
),
@ -60,7 +69,13 @@ class CustomSettingOptionsTile extends StatelessWidget {
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});
const CustomSettingOptionsTile(
{super.key,
required this.leadingWidget,
required this.onTap,
required this.titleText,
this.needBorderBelow = false,
this.isForLanguage = false});
@override
Widget build(BuildContext context) {
@ -76,7 +91,9 @@ class CustomSettingOptionsTile extends StatelessWidget {
titleText.toText(fontSize: 16),
],
),
isForLanguage ? const Icon(Icons.language, size: 18) : const Icon(Icons.arrow_forward, size: 18)
isForLanguage
? const Icon(Icons.language, size: 18)
: const Icon(Icons.arrow_forward, size: 18)
],
).onPress(onTap),
5.height,

@ -5,6 +5,7 @@ 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';
@ -22,7 +23,7 @@ class SettingOptionsLanguage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "More",
title: LocaleKeys.more.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
@ -39,8 +40,9 @@ class SettingOptionsLanguage extends StatelessWidget {
Column(
children: [
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.quickreply_outlined, size: 20),
titleText: "Requests",
leadingWidget:
const Icon(Icons.quickreply_outlined, size: 20),
titleText: LocaleKeys.requests.tr(),
needBorderBelow: true,
onTap: () {
context.read<DashboardVmCustomer>().onNavbarTapped(4);
@ -48,20 +50,22 @@ class SettingOptionsLanguage extends StatelessWidget {
}),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: "Settings",
titleText: LocaleKeys.settings.tr(),
needBorderBelow: true,
onTap: () {},
//navigateWithName(context, AppRoutes.settingOptionsInviteFriends),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.question_mark_outlined, size: 20),
titleText: "Help",
leadingWidget:
const Icon(Icons.question_mark_outlined, size: 20),
titleText: LocaleKeys.help.tr(),
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsHelp),
onTap: () =>
navigateWithName(context, AppRoutes.settingOptionsHelp),
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.person, size: 20),
titleText: "Account",
titleText: LocaleKeys.account.tr(),
needBorderBelow: false,
onTap: () {
navigateWithName(context, AppRoutes.profileView);
@ -69,20 +73,29 @@ class SettingOptionsLanguage extends StatelessWidget {
// Navigator.pop(context);
}),
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
).toWhiteContainer(
width: double.infinity,
pading: const EdgeInsets.all(12),
borderRadius: 0),
10.height,
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.translate, size: 20),
titleText: "Language",
titleText: LocaleKeys.language.tr(),
isForLanguage: true,
onTap: () {
if (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA") {
if (EasyLocalization.of(context)
?.currentLocale
?.countryCode ==
"SA") {
context.setLocale(const Locale("en", "US"));
} else {
context.setLocale(const Locale('ar', 'SA'));
}
},
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
).toWhiteContainer(
width: double.infinity,
pading: const EdgeInsets.all(12),
borderRadius: 0),
10.height,
(AppState().currentAppType == AppType.provider)
? Column(
@ -96,12 +109,13 @@ class SettingOptionsLanguage extends StatelessWidget {
color: MyColors.primaryColor,
),
),
titleText: "My Subscriptions",
titleText: LocaleKeys.mySubscriptions.tr(),
subTitle: "Silver",
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.mySubscriptionsPage);
navigateWithName(
context, AppRoutes.mySubscriptionsPage);
},
),
CustomSettingOptionsTile(
@ -113,12 +127,13 @@ class SettingOptionsLanguage extends StatelessWidget {
// color: MyColors.primaryColor,
),
),
titleText: "Subscriptions",
titleText: LocaleKeys.subscriptions.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.subscriptionsPage);
navigateWithName(
context, AppRoutes.subscriptionsPage);
},
),
CustomSettingOptionsTile(
@ -130,18 +145,24 @@ class SettingOptionsLanguage extends StatelessWidget {
// color: MyColors.primaryColor,
),
),
titleText: "Define Licenses",
titleText: LocaleKeys.defineLicenses.tr(),
subTitle: null,
isForLanguage: false,
needBorderBelow: false,
onTap: () {
navigateWithName(context, AppRoutes.providerLicensePage);
navigateWithName(
context, AppRoutes.providerLicensePage);
},
)
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0)
).toWhiteContainer(
width: double.infinity,
pading: const EdgeInsets.all(12),
borderRadius: 0)
: SizedBox(),
(AppState().currentAppType == AppType.provider)
? 10.height
: SizedBox(),
(AppState().currentAppType == AppType.provider) ? 10.height : SizedBox(),
],
)),
// : Expanded(
@ -167,7 +188,9 @@ class SettingOptionsLanguage extends StatelessWidget {
// ],
// ),
// ),
(AppState().currentAppType == AppType.provider) ? const Text("Provider") : const Text("Customer"),
(AppState().currentAppType == AppType.provider)
? Text(LocaleKeys.provider.tr())
: Text(LocaleKeys.customer.tr()),
Row(
children: [
Expanded(
@ -177,7 +200,7 @@ class SettingOptionsLanguage extends StatelessWidget {
isFilled: false,
fontSize: 16,
maxHeight: 55,
title: "Log Out",
title: LocaleKeys.logOut.tr(),
onPressed: () {},
),
),

@ -1,18 +1,22 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:local_auth/local_auth.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.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/utils/navigator.dart';
import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/button/show_image_button.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class LoginMethodSelectionPage extends StatefulWidget {
@ -54,12 +58,14 @@ class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
Expanded(
child: ShowImageButton(
onClick: () {
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType, loginType: "3" );
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType, loginType: "3");
//userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
},
title: LocaleKeys.fingerPrint.tr(),
icon: MyAssets.icFingerprintSvg,
isDisabled: userVM.isBioAvailable(Platform.isAndroid ? BiometricType.weak : BiometricType.fingerprint, ),
isDisabled: userVM.isBioAvailable(
Platform.isAndroid ? BiometricType.weak : BiometricType.fingerprint,
),
),
),
20.width,
@ -67,7 +73,7 @@ class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
child: ShowImageButton(
onClick: () {
// userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType);
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType, loginType: "4" );
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType, loginType: "4");
},
title: LocaleKeys.faceRecognition.tr(),
icon: MyAssets.icFace,
@ -82,7 +88,7 @@ class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
Expanded(
child: ShowImageButton(
onClick: () {
userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType,loginType: "1");
userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType, loginType: "1");
},
title: LocaleKeys.SMS.tr(),
icon: MyAssets.icSmsSvg,
@ -101,6 +107,16 @@ class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
),
],
),
150.height,
("Login To Another Account")
.toText(
fontSize: 20,
letterSpacing: -1.44,
)
.onPress(() {
userVM.otherLogin(context);
}),
30.height,
],
),
),

Loading…
Cancel
Save