diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c0594da..9182924 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -567,16 +567,8 @@ "logOut": "تسجيل الخروج", "customer": "العميل", "amountVAR": "كمية", - - - - - - - - - - "accept": "قبول", - "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل." + "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.", + "acceptOfferConfirmation": "هل تريد قبول هذا العرض؟", + "acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض." } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 3409f5f..75e0498 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -567,5 +567,7 @@ "customer": "Customer", "accept": "Accept", "amountVAR": "Amount", - "requestAlreadyInProgress": "This request is already in progress." + "requestAlreadyInProgress": "This request is already in progress.", + "acceptOfferConfirmation": "Do you want to accept this offer?", + "acceptOfferConfirmationMessage": "This offer will be accepted and you will pay the requested amount to the buyer in given time or else this offer will be cancelled." } \ No newline at end of file diff --git a/lib/classes/app_state.dart b/lib/classes/app_state.dart index 89e75de..adb79fc 100644 --- a/lib/classes/app_state.dart +++ b/lib/classes/app_state.dart @@ -17,6 +17,14 @@ class AppState { bool? get getIsLogged => isLogged; + String? _deviceToken; + + String? get getDeviceToken => _deviceToken; + + set setDeviceToken(String value) { + _deviceToken = value; + } + AppType currentAppType = AppType.provider; UserType userType = UserType.customer; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 58c89a8..b41d2b4 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,3 +1,4 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/generated/codegen_loader.g.dart'; @@ -172,6 +173,7 @@ class GlobalConsts { static String demandAmountError = "Amount Cannot be Empty"; static String reservationCancelError = "Cancellation Reason Cannot be Empty"; static String descriptionError = "Description Cannot be Empty"; + static String acceptingThisOffer = "I am accepting this offer."; static String vehicleVinError = "Vehicle VIN Cannot be Empty"; static String vehicleTitleError = "Vehicle Title Cannot be Empty"; static String warrantyError = "Warranty Duration Cannot be Empty"; @@ -294,3 +296,18 @@ class MyFonts { static const poppinsFont = "packages/mc_common_app/Poppins"; static const gessTwoFont = "packages/mc_common_app/GessTwo"; } + +class SignalrConsts { + + // Requests + static String receiveMessageRequestOffer = "ReceiveMessageRequestOffer"; + static String sendMessageRequestOffer = "SendMessageRequestOffer"; + + // Ads + static String sendMessageAds = "SendMessageAds"; + static String receiveMessageAds = "ReceiveMessageAds"; + + // General + static String sendMessageGeneral = "SendMessageGeneral"; + static String receiveMessageGeneral = "ReceiveMessageGeneral"; +} diff --git a/lib/config/dependencies.dart b/lib/config/dependency_injection.dart similarity index 80% rename from lib/config/dependencies.dart rename to lib/config/dependency_injection.dart index a16b30b..aea3bcc 100644 --- a/lib/config/dependencies.dart +++ b/lib/config/dependency_injection.dart @@ -1,6 +1,8 @@ // import 'package:firebase_crashlytics/firebase_crashlytics.dart'; // import 'package:flutter/material.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:injector/injector.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; @@ -12,6 +14,7 @@ import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/payments_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; +import 'package:mc_common_app/services/firebase_service.dart'; import 'package:mc_common_app/services/payments_service.dart'; import '../repositories/request_repo.dart'; @@ -25,6 +28,10 @@ class AppDependencies { injector.registerSingleton(() => ApiClientImp()); injector.registerSingleton(() => CommonServicesImp()); injector.registerSingleton(() => PaymentServiceImp()); + injector.registerSingleton(() => FirebaseMessagingServiceImp( + firebaseMessaging: FirebaseMessaging.instance, + flutterLocalNotifications: FlutterLocalNotificationsPlugin(), + )); //repos injector.registerSingleton(() => UserRepoImp()); @@ -35,5 +42,7 @@ class AppDependencies { injector.registerSingleton(() => AppointmentRepoImp()); injector.registerSingleton(() => ChatRepoImp()); injector.registerSingleton(() => BranchRepoImp()); + + // } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index ae8892a..f3f8475 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,3 +1,4 @@ +import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/requests_models/offers_model.dart'; import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'; import 'package:mc_common_app/models/requests_models/request_model.dart'; @@ -50,11 +51,9 @@ class AppRoutes { static const String changeEmailPage = "/changeEmailPage"; static const String editAccountPage = "/editAccoundPage"; - static const String dashboard = "/dashboard"; static const String bookProviderAppView = "/bookProviderAppView"; - // Appoinments static const String appointmentDetailView = "/appointmentDetailView"; static const String bookAppointmenServicesView = "/bookAppointmenServicesView"; @@ -146,7 +145,7 @@ class AppRoutes { }; } -class ChatViewArguments { +class ChatViewArgumentsForRequest { final int? requestId; final ChatTypeEnum chatTypeEnum; final String senderId; @@ -155,7 +154,7 @@ class ChatViewArguments { final int requestIndex; final RequestModel? requestModel; - ChatViewArguments({ + ChatViewArgumentsForRequest({ required this.chatTypeEnum, this.requestId, required this.senderId, @@ -166,6 +165,24 @@ class ChatViewArguments { }); } +class ChatViewArgumentsForAd { + final AdDetailsModel? adDetailsModel; + + ChatViewArgumentsForAd({required this.adDetailsModel}); +} + +class ChatViewArguments { + final ChatViewArgumentsForAd? chatViewArgumentsForAd; + final ChatViewArgumentsForRequest? chatViewArgumentsForRequest; + final ChatTypeEnum chatTypeEnum; + + ChatViewArguments({ + this.chatViewArgumentsForAd, + this.chatViewArgumentsForRequest, + required this.chatTypeEnum, + }); +} + class OfferListPageArguments { final List serviceProviderOffers; final int? requestId; diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 06c511a..95718f0 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -6,7 +6,7 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader { +class CodegenLoader extends AssetLoader{ const CodegenLoader(); @override @@ -14,1122 +14,1152 @@ class CodegenLoader extends AssetLoader { return Future.value(mapLocales[locale.toString()]); } - static const Map ar_SA = { - "firstTimeLogIn": "تسجيل الدخول لأول مره", - "signUp": "التسجيل", - "changeMobile": "تغيير رقم الجوال", - "notifications": "الاشعارات", - "general": "عام", - "defineLicences": "تحديد الرخص", - "dealershipSettings": "اعدادات البيع", - "changePassword": "تغيير كلمة المرور", - "retrievePassword": "استرجاع كلمة المرور", - "changeEmail": "تغيير الايميل", - "verify": "تحقق", - "verified": "تم التحقق", - "signOut": "تسجيل خروج", - "enterEmail": "ادخل الايميل", - "enterNewEmail": "ادخل ايميل جديد", - "enterCurrentPassword": "كلمة المرور الحاليه", - "enterNewPassword": "كلمة المرور الجديده", - "enterOldPassword": "كلمة المرور القديمه", - "confirm": "تأكيد", - "enterNewPhoneNumber": "رقم جوال جديد", - "completeProfile": "الملف الشخصي", - "continu": "استمرار", - "confirmPassword": "تأكيد كلمة المرور", - "createPassword": "انشاء كلمة مرور جديده", - "email": "ايميل", - "firstName": "الأسم الأول *", - "surname": "اسم العائله *", - "confirmPass": "تأكيد كلمة المرور *", - "createPass": "انشاء كلمة مرور جديده *", - "newPassword": " كلمة مرور جديده", - "forgetPassword": "نسيت كلمة المرور", - "forgetPasswordRecover": "نسيت كلمة المرور؟ استعادة", - "editAccount": "تعديل الحساب", - "change": "تغيير", - "verifyAccount": "التحقق من الحساب", - "login": "تسجيل دخول", - "welcomeMessage": "مرحبا", - "forgetPass": "نسيت كلمة المرور ؟", - "enterPhoneNumber": "رقم جوال ", - "phoneNumberVerified": "تم التحقق من الجوال", - "verifyNewPassword": "التحقق من كلمة المرور", - "EnterPass": "ادخل كلمة المرور", - "alreadySigned": " تم تسجيل الدخول", - "emailChangedSuccessfully": "تم تغيير الايميل بنجاح", - "passwordIsUpdated": "تم تحجيث كلمة المرور", - "passwordShouldContains": "كلمة المرور يجب ان تحتوي على رمز رقم حرف كبير حرف صغير", - " successfullyRegistered": "تم التسجيل بنجاح", - "pleaseEnterSamePassword": "ادخل كلمة مرور مطابقه", - "firstNameMandatory": "ادخل الأسم الأول ", - "surnameNameMandatory": "ادخل اسم العائله", - "passwordNameMandatory": "ادخل كلمة المرور", - "enterValidEmail": "ادخل ايميل صحيح", - "pleaseAcceptTerms": "يجب الموافقه على الشروط", - "emailVerified": "تم التحقق من الايميل بنجاح", - "selectMethod": "اختر", - "emailAddress": "ايميل", - "loginSelection": "اختر", - "selectCountryCode": "اختر رمز الدوله", - "selectProviderRole": "اختر نوع الخدمه", - "addPhoneNo": "اضف الهاتف", - "onlyCustomerApp": "نأسف هذا التطبيق فقط للعملاء", - "imageUploaded": "تم تحميل الصوره", - "fileLarger": "1KB حجم الملف اكبر من", - "account": "الحساب", - "edit": "تعديل", - "imageDeleted": "تم حذف الصوره", - "dashboard": "الصفحه الرئيسيه", - "termsOfService": "من خلال إنشاء حساب فإنك توافق على", - "userInformation": "معلومات المتسخدم", - "faceRecognition": "تحقق مع بصمة الوجه", - "fingerPrint": "تحقق مع بصمة الاصبع", - "whatsapp": "تحقق مع Whatsapp", - "SMS": "رسائل قصيره", - "selectRole": "حدد الدور", - "userRoleOrTitle": "عنوان المستخدم", - "codeSentToEmail": "تم ارسال الرمز للايميل", - "number": "موبايل", - "english": "عربي", - "title": "مرحبًا", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "انقر فوق لي", - "profile": { - "reset_password": {"label": "إعادة تعيين كلمة المرور", "username": "اسم المستخدم", "password": "كلمة المرور"} - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": {"zero": "Your amount : {} ", "one": "Your amount : {} ", "two": "Your amount : {} ", "few": "Your amount : {} ", "many": "Your amount : {} ", "other": "Your amount : {} "}, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} - }, - "reset_locale": "إعادة ضبط اللغة", - "welcomeDes": "أنت مكان واحد لكل ما تحتاجه سيارتك", - "log_in": "تسجيل الدخول", - "send": "إرسال", - "phoneNumber": "رقم الهاتف", - "forgetPasswordQ": "نسيت كلمة المرور؟", - "recover": "استعادة", - "retrivePassword": "استرجع كلمة المرور بإحدى الطرق التالية", - "retriveOnPhone": "سوف نرسل الاختيار إلى رقم هاتفك المحمول المسجل", - "retriveOnEmail": "سوف نرسل الاختيار إلى عنوان بريدك الإلكتروني المسجل", - "enterPhoneForVerfication": "الرجاء إدخال رقم هاتفك وسنرسل لك رمز التحقق", - "welcomeBack": "مرحبًا بعودتك!!!", - "selectYourCountry": "اختر بلدك", - "chooseCountry": "اختر الدوله", - "terms": "بنود الخدمة وخصوصية السياسة", - "profileMsg": "أدخل التفاصيل أدناه وأكمل معلومات الملف الشخصي", - "save": "حفظ", - "insert_otp_code": "ادخل الرمز", - "type_code": "الرجاء كتابة الرمز الذي أرسلناه إلى", - "resend_code": "أعد إرسال الرمز", - "check_code": "التحقق من الشفرة", - "time_will_expire": "إعادة إرسال الرمز بتنسيق", - "sec": "ثانية", - "providers": "الموفرون", - "appointments": "تعيينات", - "home": "بيت", - "ads": "إعلانات", - "settings": "إعدادات", - "view_all": "مشاهدة الكل", - "my_active_Ads": "إعلاناتي النشطة", - "recommended_ads": "الإعلانات الموصى بها", - "upcoming_appointment": "الموعد القادم", - "my_service_providers": "مزودي الخدمة الجدد", - "appointment_details": "تفاصيل الموعد", - "no_city_available": "لا توجد مدينة متاحة لهذا البلد", - "branch_created": "تم إنشاء الفرع بنجاح", - "branch_updated": "تم تحديث الفرع بنجاح", - "branch_deleted": "تم حذف الفرع بنجاح", - "dashboard_main": "لوحة القيادة / الصفحة الرئيسية", - "logo_brand": "الشعار / العلامة التجارية", - "remove": "إزالة", - "no_branch": "لم يتم إضافة فرع حتى الآن", - "login_once": "الرجاء تسجيل الدخول مرة واحدة", - "defineLicenese": "تحميل التراخيص والشهادات", - "description": "وصف", - "attachFile": "أرفق ملف", - "branchLocation": "معلومات الفرع والموقع", - "tapToEdit": "انقر للتعديل", - "myServiceBranches": "فروع خدمتي", - "enter_licence_detail": "الرجاء إدخال تفاصيل السجلات التجارية وإرفاق صور الترخيص", - "country": "بلد", - "city": "مدينة", - "editServices": "تحرير الخدمات", - "maintenance": "صيانة", - "accessories_modifications": "الملحقات والتعديلات", - "my_recent_providers": "مزودي الخدمة الجدد", - "my_active_ads": "إعلاناتي النشطة", - "recommended_Ads": "الإعلانات الموصى بها", - "location": "موقع", - "address": "عنوان", - "branchName": "اسم الفرع", - "branchDescription": "وصف الفرع", - "branchInfo": "معلومات الفرع", - "defineServices": "تحديد الخدمات", - "defineBranches": "تحديد الفروع", - "defineProviders": "تحديد الموفرين", - "closeAccount": "حساب مغلق", - "selectServiceCategory": "حدد فئة الخدمة", - "selectService": "حدد الخدمة", - "selectBranch": "حدد الفرع", - "createBranch": "إنشاء فرع", - "updateBranch": "تحديث فرع", - "branches": "الفروع", - "requests": "الطلبات", - "noBranchFound": "لم يتم العثور على فرع", - "onlyProviderApp": "نأسف هذا التطبيق فقط لمقدمي الخدمات", - "pickAddress": "اختر العنوان", - "pickLocation": "اختر الموقع", - "chooseCity": "اختر المدينه", - "selectAttachment": "اختيار مرفق", - "somethingWrong": "هناك خطأ ما", - "documentsUploaded": "تم ارفاق الملف بنجاح", - "update": "تحديث", - "profileCompleted": "الملف الشخصي مكتمل", - "selectLocationMap": "اختر الموقع", - "licensesAndCertifications": "الرخص و الشهادات", - "completeProfile1": "اكمل الملف الشخصي 1/3", - "completeProfile2": "اكمل الملف الشخصي 2/3", - "completeProfile3": "اكمل الملف الشخصي 3/3", - "provider": "مزود", - "noRequeststoShow": "لا توجد طلبات للعرض", - "myBranches": "فروعي", - "mergeAppointments": "دمج المواعيد", - "addService": "أضف الخدمة", - "selectServicestoAdd": "حدد الخدمات التي تريد إضافتها", - "noServiceFound": "لم يتم العثور على الخدمة", - "selectItems": "اختيار العناصر", - "noItemSelectedYet": "لم يتم تحديد أي عنصر بعد", - "totalAdditionalAmount": "إجمالي المبلغ الإضافي", - "sar": "ريال سعودي", - "cancel": "يلغي", - "add": "يضيف", - "itemsAddedSuccessfully": "تمت إضافة العناصر بنجاح", - "pleaseSelectItems": "يرجى اختيار العناصر", - "totalAmount": "المبلغ الإجمالي", - "searchItems": "البحث عن العناصر", - "addSelectedItems": "إضافة العناصر المحددة", - "collectMoneyBefore": "هل ترغب في جمع المال قبل تقديم الخدمات؟", - "yes": "نعم", - "no": "لا", - "reason": "السبب", - "typeHere": "اكتب هنا...", - "pleaseSelectReason": "يرجى تحديد السبب", - "noAppointmentFound": "لم يتم العثور على مواعيد", - "slotsOverview": "نظرة عامة على الفتحات", - "empty": "فارغ", - "occupied": "محجوز", - "totalSlots": "إجمالي الفتحات", - "selectAppointments": "اختيار المواعيد", - "appointmentMergeSuccessfully": "دمج المواعيد تم بنجاح", - "updateAppointment": "تحديث الموعد", - "addNewService": "إضافة خدمة جديدة", - "waitingPaymentfromtheCustomer": "في انتظار الدفع من العميل", - "appointmentisCompleted": "تم اكتمال الموعد", - "workStart": "بدء العمل", - "payNow": "ادفع الآن", - "arrived": "وصل", - "payLater": "ادفع لاحقًا", - "complete": "اكتمل", - "makeAnOffer": "قدم عرضًا", - "enterAmount": "أدخل المبلغ", - "submit": "إرسال", - "viewChat": "عرض الدردشة", - "requestDetail": "تفاصيل الطلب", - "sendOffer": "إرسال عرض", - "offer": "عرض", - "sendPriceOffer": "إرسال عرض السعر", - "comment": "تعليق", - "sendOTP": "إرسال رمز OTP", - "noUserAddedYet": "لم يتم إضافة مستخدم بعد", - "assignDealerUser": "تعيين مستخدم تاجر", - "createNewUser": "إنشاء مستخدم جديد", - "dealerUser": "مستخدم تاجر", - "setorEditBranchSchedule": "تعيين أو تحرير جدول الفروع", - "addServices": "إضافة خدمات", - "noServiceAddedYet": "لم تتم إضافة خدمات بعد", - "selectDays": "اختيار الأيام", - "addSelectedDays": "إضافة الأيام المحددة", - "select_Services": "اختيار الخدمات", - "searchService": "البحث عن الخدمة", - "addSelectedServices": "إضافة الخدمات المحددة", - "nameofSchedule": "اسم الجدول الزمني", - "startingDate": "تاريخ البدء", - "endDate": "تاريخ الانتهاء", - "offDays": "أيام الراحة", - "shiftStartTime": "وقت بدء الوردية", - "shiftEndTime": "وقت انتهاء الوردية", - "slotsTime": "وقت الفتحات", - "appointmentPerSlot": "موعد لكل فتحة", - "create": "إنشاء", - "pleaseEnterValidScheduleName": "يرجى إدخال اسم جدول صالح", - "pleaseSelectServices": "يرجى اختيار الخدمات", - "pleaseSelectStartDate": "يرجى تحديد تاريخ البدء", - "pleaseSelectEndDate": "يرجى تحديد تاريخ الانتهاء", - "pleaseSelectOffDays": "يرجى تحديد أيام الراحة", - "pleaseSelectStartTime": "يرجى تحديد وقت بدء الوردية", - "pleaseSelectEndTime": "يرجى تحديد وقت انتهاء الوردية", - "pleaseSelectSlotTime": "يرجى تحديد وقت الفتحة", - "pleaseSelectAppointmentPerSlot": "يرجى تحديد موعد لكل فتحة", - "exploreAds": "استكشاف الإعلانات", - "myAds": "إعلاناتي", - "noAppointmentstoShow": "لا توجد مواعيد لعرضها", - "myRecommendedAds": "الإعلانات الموصى بها لي", - "model": "الموديل", - "chooseImageSource": "اختر مصدر الصورة", - "camera": "الكاميرا", - "gallery": "المعرض", - "imageIsDeleted": "تم حذف الصورة", - "myRequests": "طلباتي", - "branchDetail": "تفاصيل الفرع", - "time": "الوقت", - "openMapLocation": "فتح موقع الخريطة", - "providerProfile": "ملف المزود", - "servicesOffer": "الخدمات المقدمة", - "noServicesAvailable": "لا تتوفر خدمات", - "bookAppointment": "حجز موعد", - "allowingHomeService": "السماح بخدمة منزلية", - "homeServiceRange": "نطاق الخدمة المنزلية", - "chargesPerKM": "الرسوم لكل كيلومتر", - "providerDetails": "تفاصيل المزود", - "someDescriptionExperienceandtheirReputation": "بعض الوصف عن المزود وسنوات خبرتهم وسمعتهم", - "availableforAppointment": "متاح للموعد", - "allowingWorkshopService": "السماح بخدمة ورشة العمل", - "serviceAmount": "مبلغ الخدمة", - "youNeedStoragePermissionFiles": "تحتاج إلى منح إذن التخزين لاختيار الملفات.", - "settingDeniedPermanently": "تم رفض هذا الإذن بشكل دائم، يرجى الذهاب إلى الإعدادات والسماح.", - "openAppSetting": "افتح إعدادات التطبيق", - "adDuration": "مدة الإعلان", - "startDate": "تاريخ البدء", - "contactDetails": "تفاصيل الاتصال", - "showyournumbertoBuyers": "هل تريد إظهار رقمك للمشترين؟", - "isNumberRegisteredWhatsApp": "هل هذا الرقم مسجل على واتساب؟", - "selectSpecialServices": "اختر الخدمات الخاصة", - "vehicleDetails": "تفاصيل المركبة", - "vehicleModel": "طراز المركبة", - "vehicleColor": "لون المركبة", - "vehicleCategory": "فئة المركبة", - "vehicleTransmission": "نقل المركبة", - "vehicleCountry": "بلد المركبة", - "vehicleAmount": "مبلغ المركبة", - "vehicleTitle": "عنوان المركبة", - "financeAvailable": "التمويل متاح", - "vehiclePictures": "صور المركبة", - "vehiclePart": "جزء المركبة", - "damagePartPictures": "صور الأجزاء المتضررة", - "vehicleDamagePart": "جزء المركبة المتضرر", - "duration": ":المدة", - "specialServices": "الخدمات الخاصة", - "specialService": "خدمة خاصة", - "adContactDetails": "تفاصيل الاتصال بالإعلان", - "onWhatsAp": "على واتساب", - "reserveAdPriceInfo": "معلومات سعر الإعلان المحجوز", - "addDamagePart": "إضافة جزء متضرر", - "vehicleType": "نوع المركبة", - "vehicleYear": "سنة المركبة", - "vehicleCondition": "حالة المركبة", - "vehicleMileage": "عدد الأميال للمركبة", - "sellerType": "نوع البائع", - "vehicleCity": "مدينة المركبة", - "vehicleVIN": "رقم تعريف المركبة (VIN)", - "warrantyAvailable": "الضمان متاح", - "years": "سنوات", - "vehicleDetail": "تفاصيل المركبة", - "vehicleBrand": "ماركة المركبة", - "vehicleModelYear": "سنة طراز المركبة", - "vehicleSellerType": "نوع بائع المركبة", - "demandAmount": "المبلغ المطلوب", - "warrantyAvailableYears": "الضمان متاح (عدد السنوات)", - "vehicleDescription": "وصف المركبة", - "attachImage": "إرفاق صورة", - "useFingerPrintFaceID": "يرجى استخدام بصمة الإصبع أو معرف الوجه", - "setupTouchID": "يرجى إعداد معرف اللمس", - "reenableTouchID": "يرجى إعادة تمكين معرف اللمس", - "scanFaceIDAuthenticate": "امسح بصمة الإصبع أو معرف الوجه للتحقق", - "AdDeletedSuccessfully": "تم حذف الإعلان بنجاح!", - "yourReservationCancelled": "تم إلغاء حجزك.", - "adDeactivatedSuccessfully": "تم إلغاء تفعيل الإعلان بنجاح!", - "vehicle": { - "selectVehicleType": "يرجى اختيار نوع السيارة", - "selectVehicleModel": "يرجى اختيار طراز السيارة", - "selectVehicleModelYear": "يرجى اختيار سنة طراز السيارة", - "selectVehicleColor": "يرجى اختيار لون السيارة", - "vehicleCondition": "يرجى اختيار حالة السيارة", - "vehicleCategory": "يرجى اختيار فئة السيارة", - "vehicleMileage": "يرجى اختيار عدد أميال السيارة", - "vehicleTransmission": "يرجى اختيار نوع ناقل الحركة", - "vehicleSellerType": "يرجى اختيار نوع بائع السيارة", - "selectAny": "يرجى اختيار أي خيار", - "vehicleCity": "يرجى اختيار مدينة السيارة", - "vehiclePart": "يرجى اختيار جزء السيارة", - "selectValidVehicleType": "يرجى اختيار نوع سيارة صالح" - }, - "selectAppointmentTimeService": "يجب عليك اختيار وقت الموعد للخدمة.", - "error": "خطأ", - "appointmentBookedSuccessfully": "تم حجز موعدك بنجاح", - "appointmentStatusUpdated": "تم تحديث حالة الموعد", - "paymentStatusUpdated": "تم تحديث حالة الدفع", - "selectOneSubService": "يرجى اختيار خدمة فرعية واحدة على الأقل", - "chargesBreakdown": "تفاصيل الرسوم", - "services": "الخدمات", - "homeLocation": "الموقع المنزلي", - "selectAppointmentTime": "يجب عليك اختيار وقت الموعد لكل موعد في الجدول", - "noAppointmentAvailable": "لا توجد مواعيد متاحة للعناصر المحددة", - "changedMind": "لقد غيرت رأيي", - "veryHighPrice": "السعر مرتفع جداً", - "alreadySold": "تم البيع بالفعل", - "otherVar": "أخرى", - "paymentSuccessful": "تم الدفع بنجاح", - "paymentFailed": "فشل الدفع!", - "requestSuccessfullyCreated": "تم إنشاء الطلب بنجاح", - "selectValidRequestType": "يرجى اختيار نوع طلب صالح", - "selectValidBrand": "يرجى اختيار علامة تجارية صالحة", - "selectValidModel": "يرجى اختيار طراز صالح", - "selectValidYear": "يرجى اختيار سنة صالحة", - "selectValidCountry": "يرجى اختيار بلد صالح", - "selectValidCity": "يرجى اختيار مدينة صالحة", - "addValidPrice": "يرجى إضافة سعر صالح", - "addValidDescription": "يرجى إضافة وصف صالح", - "passwordTooShort": "كلمة المرور الخاصة بك قصيرة جدًا", - "passwordAcceptableStrong": "كلمة المرور الخاصة بك مقبولة ولكنها ليست قوية", - "passwordIsStrong": "كلمة المرور الخاصة بك قوية", - "passwordVeryStrong": "كلمة المرور الخاصة بك قوية جدًا", - "selectDuration": "اختر المدة", - "daysVar": "الأيام", - "adCharges": "رسوم الإعلان", - "select": "اختر", - "deleteAdConfirmation": "هل تريد حذف الإعلان؟", - "deleteAdConfirmationMessage": "سيتم حذف إعلانك نهائيًا ولا يمكنك التراجع عن هذا الإجراء", - "mileage": "المسافة المقطوعة", - "transmission": "ناقل الحركة", - "demand": "الطلب", - "adDurationExpired": "انتهت مدة عرض الإعلان الخاص بك", - "bankDetails": "تفاصيل البنك", - "bankName": "اسم البنك", - "iban": "الرقم الدولي للحساب المصرفي (IBAN)", - "rejectionComments": "تعليقات الرفض", - "editAd": "تعديل الإعلان", - "reserveAd": "حجز الإعلان", - "reservationAmount": "مبلغ الحجز", - "belowAmountPayLater": "المبلغ الذي ستدفعه لاحقًا", - "carPrice": "سعر السيارة", - "vatExcluded": "القيمة المضافة غير مشمولة", - "carInsuranceService": "خدمة التأمين على السيارة", - "toBeDecided": "لم يتم اتخاذ القرار بعد", - "registrationCarPlates": "تسجيل ولوحات السيارة", - "homeDeliveryService": "خدمة التوصيل إلى المنزل", - "specialServicechargesInsuranceDeliveryLocation": "سيتم إضافة رسوم خدمة خاصة بناءً على التأمين المطلوب وموقع التسليم", - "estimated": "مقدر", - "servicesReservingAd": "بعض الخدمات إلزامية أثناء حجز الإعلان", - "completeReservation": "إتمام الحجز", - "contact": "اتصال", - "setDateandTime": "تحديد التاريخ والوقت", - "selectOffice": "اختيار المكتب", - "availableSlots": "المواعيد المتاحة", - "bookAndPay": "الحجز والدفع", - "reservationAmounts": "مبالغ الحجز", - "tax": "الضريبة", - "adsFilter": "تصفية الإعلانات", - "searchByCity": "البحث حسب المدينة", - "selectCity": "اختر المدينة", - "searchByBrandName": "البحث حسب اسم العلامة التجارية", - "selectVehicleBrand": "اختر علامة تجارية للسيارة", - "searchByVehicleYear": "البحث حسب سنة السيارة", - "selectYear": "اختر السنة", - "searchByAdOwner": "البحث حسب مالك الإعلان", - "selectOwner": "اختر المالك", - "search": "بحث", - "clearFilters": "مسح التصفية", - "book": "حجز", - "markAsSold": "وضع علامة تم البيع", - "deactivateAd": "إلغاء تفعيل الإعلان", - "doWantDeactivateAd": "هل تريد إلغاء تفعيل هذا الإعلان؟", - "stoptheBuyers": "سنتوقف عن عرض هذا الإعلان للمشترين", - "cancelReservation": "إلغاء الحجز", - "reasonForCancellation": "سبب الإلغاء", - "doWantCancelReservation": "هل تريد إلغاء الحجز؟", - "yourAdVisibletoBuy": "سيتم إلغاء حجز إعلانك وسيكون هذا الإعلان مرئيًا للجميع مرة أخرى للشراء", - "completeDeal": "إتمام الصفقة", - "uploadBankReceipt": "تحميل إيصال البنك", - "notesForAdmin": "ملاحظات للإدارة", - "extendAd": "تمديد الإعلان", - "updateAdDetails": "هل تريد تحديث تفاصيل الإعلان", - "durationExtendingAd": "يمكنك تغيير مدة الإعلان والتفاصيل قبل تمديد الإعلان", - "waitingAdminsResponse": "في انتظار رد الإدارة", - "cancelledByOwner": "ألغيت من قبل المالك", - "cancelledByAdmin": "ألغيت من قبل الإدارة", - "reservationTimeOver": "انتهى وقت الحجز", - "paymentVerified": "تم التحقق من الدفع", - "rejectedFormAdmin": "تم الرفض من قبل الإدارة", - "waitingAdminPost": "في انتظار الإدارة للنشر", - "waitingAdminsApproval": "في انتظار موافقة الإدارة", - "sold": "تم البيع", - "noAdsShow": "لا توجد إعلانات لعرضها", - "damagePartList": "قائمة الأجزاء المتضررة", - "searchPart": "البحث عن جزء", - "addSpecialService": "إضافة خدمة خاصة", - "vehicleVar": "السيارة", - "detailsVar": "التفاصيل", - "damageVar": "الضرر", - "partsVar": "الأجزاء", - "additional": "إضافي", - "review": "مراجعة", - "adVar": "الإعلان", - "updateAd": "تحديث الإعلان", - "createAd": "إنشاء إعلان", - "next": "التالي", - "submitAd": "إرسال الإعلان", - "selectAdType": "اختر نوع الإعلان", - "validUntilSubscriptionExpiration": "صالح حتى انتهاء الاشتراك", - "adsRemainingVar": "الإعلانات المتبقية", - "youLeftAdsGivenSubscription": "لقد بقي لديك 05 من 50 إعلانًا في الاشتراك.", - "updateSubscription": "تحديث الاشتراك", - "workInProgress": "العمل جارٍ", - "visitCompleted": "تمت الزيارة", - "youWantCancelAppointment": "هل تريد إلغاء هذا الموعد؟", - "appointmentCancelledCannotUndoAction": "سيتم إلغاء موعدك ولا يمكنك التراجع عن هذا الإجراء", - "appointment": "الموعد", - "rescheduleAppointment": "إعادة جدولة الموعد", - "payforAppointment": "دفع ثمن الموعد", - "appointmentsFilter": "تصفية المواعيد", - "searchByProvider": "البحث حسب المزود", - "selectProvider": "اختر المزود", - "searchByBranch": "البحث حسب الفرع", - "searchByCategory": "البحث حسب الفئة", - "selectCategory": "اختر الفئة", - "searchByService": "البحث حسب الخدمة", - "selectServices": "اختر الخدمات", - "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": "اللغة", - "mySubscription": "اشتراكاتي", - "subscriptions": "الاشتراكات", - "defineLicenses": "تحديد التراخيص", - "logOut": "تسجيل الخروج", - "customer": "العميل", - "accept": "قبول", - "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.", - "amountVAR": "كمية" - }; - static const Map en_US = { - "firstTimeLogIn": "First Time Log In", - "signUp": "Sign Up", - "changeMobile": "Change Mobile", - "notifications": "Notifications", - "general": "General", - "defineLicences": "Define Licences", - "dealershipSettings": "Dealership Settings", - "changePassword": "Change Password", - "retrievePassword": "Retrieve Password", - "changeEmail": "Change Email", - "verify": "Verify", - "verified": "Verified", - "signOut": "Sign Out", - "enterEmail": "Enter Email", - "enterNewEmail": "Enter New Email", - "enterNewPassword": "Enter New Password", - "enterCurrentPassword": "Enter Current Password", - "enterOldPassword": "Enter Old Password", - "confirm": "Confirm", - "completeProfile": "Complete Profile", - "enterNewPhoneNumber": "Enter New Phone Number", - "enterPhoneNumber": "Enter Phone Number", - "continu": "Continue", - "confirmPassword": "Confirm Password", - "createPassword": "Create Password", - "email": "Email", - "firstName": "First Name *", - "surname": "Surname *", - "confirmPass": "Confirm Password *", - "createPass": "Create Password *", - "newPassword": "New Password", - "forgetPassword": "Forget Password", - "forgetPasswordRecover": "Forget Password? Recover", - "editAccount": "Edit Account", - "change": "Change", - "verifyAccount": "Verify Account", - "login": "Log In", - "welcomeMessage": "Welcome Message", - "forgetPass": "Forget Password ?", - "phoneNumberVerified": "Phone Number Verified", - "verifyNewPassword": "Verify New Password", - "EnterPass": "Enter Password ?", - "alreadySigned": " Already Signed Up and Logged In", - "emailChangedSuccessfully": "Email is Changed Successfully", - "passwordIsUpdated": "Password is Updated", - "passwordShouldContains": "Password Should contains Character, Number, Capital and small letters,", - " successfullyRegistered": " Successfully Registered, Please login once,", - "pleaseEnterSamePassword": "Please enter same password", - "firstNameMandatory": "First name is mandatory", - "surnameNameMandatory": "Surname is mandatory", - "passwordNameMandatory": "Password is mandatory", - "enterValidEmail": "Enter Valid Email", - "pleaseAcceptTerms": "Please accept terms", - "emailVerified": "Email is verified successfully", - "selectMethod": "Select Method", - "emailAddress": "Email Address", - "loginSelection": "Login Selection", - "selectCountryCode": "Please select Country Code", - "selectProviderRole": "Please select Provider Role", - "addPhoneNo": "Please add Phone No", - "onlyCustomerApp": "Sorry, Only Customer's can log in this app", - "imageUploaded": "Image is uploaded", - "fileLarger": "File is larger then 1KB", - "account": "Account", - "edit": "EDIT", - "imageDeleted": "Image is Deleted", - "dashboard": "Dashboard/Main Page", - "termsOfService": "By creating an account you agree to our", - "userInformation": "User Information", - "faceRecognition": "Face Recognition", - "fingerPrint": "Finger Print", - "whatsapp": "With Whatsapp", - "SMS": "With SMS", - "selectRole": "Select Role", - "userRoleOrTitle": "User role or title", - "codeSentToEmail": "Code is sent to email", - "number": "Number", - "english": "English", - "title": "Hello", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "profile": { - "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"} - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": {"zero": "Your amount : {} ", "one": "Your amount : {} ", "two": "Your amount : {} ", "few": "Your amount : {} ", "many": "Your amount : {} ", "other": "Your amount : {} "}, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} - }, - "reset_locale": "Reset Language", - "welcomeDes": "You one stop place all your car needs", - "log_in": "Log In", - "send": "Send", - "phoneNumber": "Phone Number", - "forgetPasswordQ": "Forget Password?", - "recover": "Recover", - "retrivePassword": "Retrive password by one of following method", - "retriveOnPhone": "We will send the opt to your registered mobile number", - "retriveOnEmail": "We will send the opt to your registered email address", - "enterPhoneForVerfication": "Please enter your phone number We will send you the verification code", - "welcomeBack": "Welcome Back!!!", - "selectYourCountry": "Select Your Country", - "chooseCountry": "Choose Country", - "terms": "Terms of Service and Privacy Policy", - "profileMsg": "Enter the details below and complete the profile info", - "save": "Save", - "insert_otp_code": "Enter the code", - "type_code": "Please type the code we sent to", - "resend_code": "Resend Code", - "check_code": "Check Code", - "time_will_expire": "Resend code in", - "sec": "sec", - "providers": "Providers", - "appointments": "Appointments", - "home": "Home", - "ads": "Ads", - "settings": "Settings", - "view_all": "view all", - "my_active_Ads": "My Active Ads", - "recommended_ads": "Recommended Ads", - "upcoming_appointment": "Upcoming Appointment", - "my_service_providers": "My Recent Service Providers", - "appointment_details": "Appointment Details", - "no_city_available": "No City Available for this country", - "branch_created": "Branch is successfully created", - "branch_updated": "Branch is successfully Updated", - "branch_deleted": "Branch is successfully Deleted", - "dashboard_main": "Dashboard/Main Page", - "logo_brand": "Logo/Brand", - "remove": "Remove", - "no_branch": "No Branch Added Yet", - "login_once": "Please login once", - "defineLicenese": "Upload Licenses and Certificates", - "description": "Description", - "attachFile": "Attach File", - "branchLocation": "Branch info and Location", - "tapToEdit": "Tap to edit", - "myServiceBranches": "My Service Branches", - "enter_licence_detail": "Please enter the detail for commercial records and attach the license images", - "country": "Country", - "city": "City", - "editServices": "Edit Services", - "maintenance": "Maintenance", - "accessories_modifications": "Accessories and Modifications", - "my_recent_providers": "My Recent Service Providers", - "my_active_ads": "My Active Ads", - "recommended_Ads": "Recommended Ads", - "select_services": "Select services you want", - "location": "Location", - "address": "Address", - "branchName": "Branch Name", - "branchDescription": "Branch Description", - "branchInfo": "Branch Info", - "defineServices": "Define Services", - "defineBranches": "Define Branches", - "defineProviders": "Define Providers", - "closeAccount": "Close Account", - "selectServiceCategory": "Select Service Category", - "selectService": "Select Service", - "selectBranch": "Select Branch", - "createBranch": "Create Branch", - "updateBranch": "Update Branch", - "branches": "Branches", - "requests": "Requests", - "noBranchFound": "No Branch Found", - "pickAddress": "Pick Address", - "pickLocation": "Pick Location", - "chooseCity": "Select City", - "selectAttachment": "Select Attachment", - "somethingWrong": "Something went wrong", - "documentsUploaded": "Documents uploaded successfully", - "update": "Update", - "profileCompleted": "Profile is Completed", - "selectLocationMap": "Select Location Map", - "licensesAndCertifications": "licenses & certifications", - "completeProfile1": "Complete Profile 1/3", - "completeProfile2": "Complete Profile 2/3", - "completeProfile3": "Complete Profile 3/3", - "provider": "Provider", - "noRequeststoShow": "No Requests to Show", - "myBranches": "My Branches", - "mergeAppointments": "Merge Appointments", - "addService": "Add Service", - "selectServicestoAdd": "Select services you want to add", - "noServiceFound": "No Service Found", - "selectItems": "Select Items", - "noItemSelectedYet": "No Item Selected Yet", - "totalAdditionalAmount": "Total Additional Amount", - "sar": "SAR", - "cancel": "Cancel", - "add": "Add", - "itemsAddedSuccessfully": "Items are added Successfully", - "pleaseSelectItems": "Please select items", - "totalAmount": "Total Amount", - "searchItems": "Search Items", - "addSelectedItems": "Add Selected Items", - "collectMoneyBefore": "Do you want to collect the money before providing services?", - "yes": "Yes", - "no": "No", - "reason": "Reason", - "typeHere": "Type Here...", - "pleaseSelectReason": "Please Select Reason", - "noAppointmentFound": "No Appointment Found", - "slotsOverview": "Slots Overview", - "empty": "Empty", - "occupied": "Occupied", - "totalSlots": "Total Slots", - "selectAppointments": "Select Appointments", - "appointmentMergeSuccessfully": "Appointment Merge is Successfully done", - "updateAppointment": "Update Appointment", - "addNewService": "Add New Service", - "waitingPaymentfromtheCustomer": "Waiting for the payment from the customer", - "appointmentisCompleted": "Appointment is completed", - "workStart": "Work Start", - "payNow": "Pay Now", - "arrived": "Arrived", - "payLater": "Pay Later", - "complete": "Complete", - "makeAnOffer": "Make an offer", - "enterAmount": "Enter amount", - "submit": "Submit", - "viewChat": "View Chat", - "requestDetail": "Request Detail", - "sendOffer": "Send Offer", - "offer": "Offer", - "sendPriceOffer": "Send Price Offer", - "comment": "Comment", - "sendOTP": "Send OTP", - "noUserAddedYet": "No User Added Yet", - "assignDealerUser": "Assign Dealer User", - "createNewUser": "Create New User", - "dealerUser": "Dealer User", - "setorEditBranchSchedule": "Set or Edit Branch Schedule", - "addServices": "Add Services", - "noServiceAddedYet": "No Service Added Yet", - "selectDays": "Select Days", - "addSelectedDays": "Add Selected Days", - "select_Services": "Select Services", - "searchService": "Search Service", - "addSelectedServices": "Add Selected Services", - "nameofSchedule": "Name of Schedule", - "startingDate": "Starting Date", - "endDate": "End Date", - "offDays": "Off Days", - "shiftStartTime": "Shift Start Time", - "shiftEndTime": "Shift End Time", - "slotsTime": "Slots Time", - "appointmentPerSlot": "Appointment Per Slot", - "create": "Create", - "pleaseEnterValidScheduleName": "Please enter valid schedule Name", - "pleaseSelectServices": "Please select Services", - "pleaseSelectStartDate": "Please select start date", - "pleaseSelectEndDate": "Please select end date", - "pleaseSelectOffDays": "Please Select off Days", - "pleaseSelectStartTime": "Please select start time", - "pleaseSelectEndTime": "Please select end time", - "pleaseSelectSlotTime": "Please select slot time", - "pleaseSelectAppointmentPerSlot": "Please select appointment per slot", - "exploreAds": "Explore Ads", - "myAds": "My Ads", - "noAppointmentstoShow": "No Appointments to show", - "myRecommendedAds": "My Recommended Ads", - "model": "Model", - "chooseImageSource": "Choose image source", - "camera": "Camera", - "gallery": "Gallery", - "imageIsDeleted": "Image is Deleted", - "myRequests": "My Requests", - "branchDetail": "Branch Detail", - "time": "Time", - "openMapLocation": "Open Map Location", - "providerProfile": "Provider Profile", - "servicesOffer": "Services Offer", - "noServicesAvailable": "No Services Available", - "bookAppointment": "Book Appointment", - "allowingHomeService": "Allowing home service", - "homeServiceRange": "Home service range", - "chargesPerKM": "Charges per KM", - "providerDetails": "Provider Details", - "someDescriptionExperienceandtheirReputation": "Some description about the provider and their years of experience and their reputation", - "availableforAppointment": "Available for appointment", - "allowingWorkshopService": "Allowing Workshop service", - "serviceAmount": "Service Amount", - "youNeedStoragePermissionFiles.": "You need to give storage permission to select files.", - "settingDeniedPermanently": "This permission was denied permanently, Please go to settings and allow. ", - "openAppSetting": "Open App Setting", - "adDuration": "Ad Duration", - "startDate": "Start Date", - "contactDetails": "Contact Details", - "showyournumbertoBuyers": "Do you want to show your number to the buyers?", - "isNumberRegisteredWhatsApp": "Is this number registered on WhatsApp?", - "selectSpecialServices": "Select Special Services", - "vehicleDetails": "Vehicle Details", - "vehicleModel": "Vehicle Model", - "vehicleColor": "Vehicle Color", - "vehicleCategory": "Vehicle Category", - "vehicleTransmission": "Vehicle Transmission", - "vehicleCountry": "Vehicle Country", - "vehicleAmount": "Vehicle Amount", - "vehicleTitle": "Vehicle Title", - "financeAvailable": "Finance Available", - "vehiclePictures": "Vehicle Pictures", - "vehiclePart": "Vehicle Part", - "damagePartPictures": "Damage Part Pictures", - "vehicleDamagePart": "Vehicle Damage Part", - "duration": "Duration:", - "specialServices": "Special Services", - "specialService": "Special Service", - "adContactDetails": "Ad Contact Details", - "onWhatsAp": "On WhatsAp", - "reserveAdPriceInfo": "Reserve Ad Price Info", - "addDamagePart": "Add Damage Part", - "vehicleType": "Vehicle Type", - "vehicleYear": "Vehicle Year", - "vehicleCondition": "Vehicle Condition", - "vehicleMileage": "Vehicle Mileage", - "sellerType": "Seller Type", - "vehicleCity": "Vehicle City", - "vehicleVIN": "Vehicle VIN", - "warrantyAvailable": "Warranty Available", - "years": "Years", - "vehicleDetail": "Vehicle Detail", - "vehicleBrand": "Vehicle Brand", - "vehicleModelYear": "Vehicle Model Year", - "vehicleSellerType": "Vehicle Seller Type", - "demandAmount": "Demand Amount", - "warrantyAvailableYears": "Warranty Available (No. of Years)", - "vehicleDescription": "Vehicle Description", - "attachImage": "Attach Image", - "useFingerPrintFaceID": "Please use your fingerprint or face ID", - "setupTouchID": "Please set up your Touch ID", - "reenableTouchID": "Please reenable your Touch ID", - "scanFaceIDAuthenticate": "Scan your fingerprint or face ID to authenticate", - "adDeletedSuccessfully": "Ad has been deleted successfully!", - "yourReservationCancelled": "Your reservation has been cancelled.", - "adDeactivatedSuccessfully": "Ad has been deactivated successfully!", - "vehicle": { - "selectVehicleType": "Please select vehicle type", - "selectVehicleModel": "Please select vehicle model", - "selectVehicleModelYear": "Please select vehicle model year", - "selectVehicleColor": "Please select vehicle color", - "vehicleCondition": "Please select vehicle condition", - "vehicleCategory": "Please select vehicle category", - "vehicleMileage": "Please select vehicle Mileage", - "vehicleTransmission": "Please select vehicle transmission", - "vehicleSellerType": "Please select vehicle seller type", - "selectAny": "Please select any", - "vehicleCity": "Please select vehicle city", - "vehiclePart": "Please select vehicle part", - "selectValidVehicleType": "Please select valid Vehicle Type" - }, - "selectAppointmentTimeService": "You must select appointment time the service.", - "error": "Error", - "appointmentBookedSuccessfully": "Your appointment has been booked successfully", - "appointmentStatusUpdated": "Appointment Status Updated", - "paymentStatusUpdated": "Payment Status Updated", - "selectOneSubService": "Please select at least one sub service", - "chargesBreakdown": "Charges Breakdown", - "services": "Services", - "homeLocation": "Home Location", - "selectAppointmentTime": "You must select appointment time for each schedule's appointment", - "noAppointmentAvailable": "There are no available appointments for selected Items", - "changedMind": "I have changed my mind", - "veryHighPrice": "Very High Price", - "alreadySold": "Already Sold", - "otherVar": "Other", - "paymentSuccessful": "Payment Successful", - "paymentFailed": "Payment Failed!", - "requestSuccessfullyCreated": "Request Successfully Created", - "selectValidRequestType": "Please select valid Request Type", - "selectValidBrand": "Please select valid Brand", - "selectValidModel": "Please select valid Model", - "selectValidYear": "Please select valid Year", - "selectValidCountry": "Please select valid Country", - "selectValidCity": "Please select valid City", - "addValidPrice": "Please add valid Price", - "addValidDescription": "Please add valid Description", - "passwordTooShort": "Your password is too short", - "passwordAcceptableStrong": "Your password is acceptable but not strong", - "passwordIsStrong": "Your password is strong", - "passwordVeryStrong": "Your password is very strong", - "onlyProviderApp": "Sorry, Only Customer's can log in this app", - "selectDuration": "Select Duration", - "daysVar": "Days", - "adCharges": "Ad Charges", - "select": "Select", - "deleteAdConfirmation": "Do you want to delete the ad?", - "deleteAdConfirmationMessage": "Your ad will be permanently deleted and you cannot undo this action", - "mileage": "mileage", - "transmission": "Transmission", - "demand": "Demand", - "adDurationExpired": "Your Ad Duration time is over", - "bankDetails": "Bank Details", - "bankName": "Bank Name", - "iban": "IBAN", - "rejectionComments": "Rejection Comments", - "editAd": "Edit Ad", - "reserveAd": "Reserve Ad", - "reservationAmount": "Reservation Amount", - "belowAmountPayLater": "Below Amount that you will pay later", - "carPrice": "Car Price", - "vatExcluded": "VAT Excluded", - "carInsuranceService": "Car insurance Service", - "toBeDecided": "To be Decided", - "registrationCarPlates": "Registration & Car Plates", - "homeDeliveryService": "Home Delivery Service", - "specialServicechargesInsuranceDeliveryLocation": "Special service charges will be added based on desired insurance and delivery Location", - "estimated": "Estimated", - "servicesReservingAd": "Some services are mandatory while reserving Ad", - "completeReservation": "Complete Reservation", - "contact": "Contact", - "setDateandTime": "Set Date and Time", - "selectOffice": "Select Office", - "availableSlots": "Available Slots", - "bookAndPay": "Book and Pay", - "reservationAmounts": "Reservation Amounts", - "tax": "Tax", - "adsFilter": "Ads Filter", - "searchByCity": "Search By City", - "selectCity": "Select City", - "searchByBrandName": "Search By Brand Name", - "selectVehicleBrand": "Select Vehicle Brand", - "searchByVehicleYear": "Search By Vehicle Year", - "selectYear": "Select Year", - "searchByAdOwner": "Search By Ad Owner", - "selectOwner": "Select Owner", - "search": "Search", - "clearFilters": "Clear Filters", - "book": "Book", - "markAsSold": "Mark As Sold", - "deactivateAd": "Deactivate Ad", - "doWantDeactivateAd": "Do you want to the Deactivate this Ad?", - "stoptheBuyers": "We will stop showing this ad to the buyers", - "cancelReservation": "Cancel Reservation", - "reasonForCancellation": "Reason for Cancellation", - "doWantCancelReservation": "Do you want to cancel the reservation", - "yourAdVisibletoBuy.": "Your ad reservation will be cancelled and this ad will be again visible to everyone to buy", - "completeDeal": "Complete Deal", - "uploadBankReceipt": "Upload Bank Receipt", - "notesForAdmin": "Notes For Admin", - "extendAd": "Extend Ad", - "updateAdDetails": "Do you want to update the Ad Details", - "durationExtendingAd": "You can change the ad duration and details before extending the ad", - "waitingAdminsResponse": "Waiting for Admins Response", - "cancelledByOwner": "Cancelled by Owner", - "cancelledByAdmin": "Cancelled by Admin", - "reservationTimeOver": "Reservation Time Over", - "paymentVerified": "Payment Verified", - "rejectedFormAdmin": "Rejected form Admin", - "waitingAdminPost": "Waiting for admin to post", - "waitingAdminsApproval": "Waiting for Admins Approval", - "sold": "Sold", - "noAdsShow": "No Ads to show", - "damagePartList": "Damage Part List", - "searchPart": "Search Part", - "addSpecialService": "Add Special Service", - "vehicleVar": "Vehicle", - "detailsVar": "Details", - "damageVar": "Damage", - "partsVar": "Parts", - "additional": "Additional", - "review": "Review", - "adVar": "Ad", - "updateAd": "Update Ad", - "createAd": "Create Ad", - "next": "Next", - "submitAd": "Submit Ad", - "selectAdType": "Select Ad Type", - "validUntilSubscriptionExpiration": "Valid Until Subscription Expiration", - "adsRemainingVar ": "Ads Remaining", - "youLeftAdsGivenSubscription": "You have left with 05 out of 50 ads given in the subscription.", - "updateSubscription": "Update Subscription", - "workInProgress": "Work In Progress", - "visitCompleted": "Visit Completed", - "youWantCancelAppointment": "Do you want to cancel this appointment?", - "appointmentCancelledCannotUndoAction": "Your appointment will be cancelled and you cannot undo this action.", - "appointment": "Appointment", - "rescheduleAppointment": "Reschedule Appointment", - "payforAppointment": "Pay for Appointment", - "appointmentsFilter": "Appointments Filter", - "searchByProvider": "Search By Provider", - "selectProvider": "Select Provider", - "searchByBranch": "Search By Branch", - "searchByCategory": "Search By Category", - "selectCategory": "Select Category", - "searchByService": "Search By Service", - "selectServices": "Select Services", - "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 Subscription", - "subscriptions": "Subscriptions", - "defineLicenses": "Define Licenses", - "logOut": "Log Out", - "customer": "Customer", - "accept": "Accept", - "amountVAR": "Amount", - "requestAlreadyInProgress": "This request is already in progress." - }; - static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; + static const Map ar_SA = { + "firstTimeLogIn": "تسجيل الدخول لأول مره", + "signUp": "التسجيل", + "changeMobile": "تغيير رقم الجوال", + "notifications": "الاشعارات", + "general": "عام", + "defineLicences": "تحديد الرخص", + "dealershipSettings": "اعدادات البيع", + "changePassword": "تغيير كلمة المرور", + "retrievePassword": "استرجاع كلمة المرور", + "changeEmail": "تغيير الايميل", + "verify": "تحقق", + "verified": "تم التحقق", + "signOut": "تسجيل خروج", + "enterEmail": "ادخل الايميل", + "enterNewEmail": "ادخل ايميل جديد", + "enterCurrentPassword": "كلمة المرور الحاليه", + "enterNewPassword": "كلمة المرور الجديده", + "enterOldPassword": "كلمة المرور القديمه", + "confirm": "تأكيد", + "enterNewPhoneNumber": "رقم جوال جديد", + "completeProfile": "الملف الشخصي", + "continu": "استمرار", + "confirmPassword": "تأكيد كلمة المرور", + "createPassword": "انشاء كلمة مرور جديده", + "email": "ايميل", + "firstName": "الأسم الأول *", + "surname": "اسم العائله *", + "confirmPass": "تأكيد كلمة المرور *", + "createPass": "انشاء كلمة مرور جديده *", + "newPassword": " كلمة مرور جديده", + "forgetPassword": "نسيت كلمة المرور", + "forgetPasswordRecover": "نسيت كلمة المرور؟ استعادة", + "editAccount": "تعديل الحساب", + "change": "تغيير", + "verifyAccount": "التحقق من الحساب", + "login": "تسجيل دخول", + "welcomeMessage": "مرحبا", + "forgetPass": "نسيت كلمة المرور ؟", + "enterPhoneNumber": "رقم جوال ", + "phoneNumberVerified": "تم التحقق من الجوال", + "verifyNewPassword": "التحقق من كلمة المرور", + "EnterPass": "ادخل كلمة المرور", + "alreadySigned": " تم تسجيل الدخول", + "emailChangedSuccessfully": "تم تغيير الايميل بنجاح", + "passwordIsUpdated": "تم تحجيث كلمة المرور", + "passwordShouldContains": "كلمة المرور يجب ان تحتوي على رمز رقم حرف كبير حرف صغير", + " successfullyRegistered": "تم التسجيل بنجاح", + "pleaseEnterSamePassword": "ادخل كلمة مرور مطابقه", + "firstNameMandatory": "ادخل الأسم الأول ", + "surnameNameMandatory": "ادخل اسم العائله", + "passwordNameMandatory": "ادخل كلمة المرور", + "enterValidEmail": "ادخل ايميل صحيح", + "pleaseAcceptTerms": "يجب الموافقه على الشروط", + "emailVerified": "تم التحقق من الايميل بنجاح", + "selectMethod": "اختر", + "emailAddress": "ايميل", + "loginSelection": "اختر", + "selectCountryCode": "اختر رمز الدوله", + "selectProviderRole": "اختر نوع الخدمه", + "addPhoneNo": "اضف الهاتف", + "onlyCustomerApp": "نأسف هذا التطبيق فقط للعملاء", + "imageUploaded": "تم تحميل الصوره", + "fileLarger": "1KB حجم الملف اكبر من", + "account": "الحساب", + "edit": "تعديل", + "imageDeleted": "تم حذف الصوره", + "dashboard": "الصفحه الرئيسيه", + "termsOfService": "من خلال إنشاء حساب فإنك توافق على", + "userInformation": "معلومات المتسخدم", + "faceRecognition": "تحقق مع بصمة الوجه", + "fingerPrint": "تحقق مع بصمة الاصبع", + "whatsapp": "تحقق مع Whatsapp", + "SMS": "رسائل قصيره", + "selectRole": "حدد الدور", + "userRoleOrTitle": "عنوان المستخدم", + "codeSentToEmail": "تم ارسال الرمز للايميل", + "number": "موبايل", + "english": "عربي", + "title": "مرحبًا", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "انقر فوق لي", + "profile": { + "reset_password": { + "label": "إعادة تعيين كلمة المرور", + "username": "اسم المستخدم", + "password": "كلمة المرور" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "إعادة ضبط اللغة", + "welcomeDes": "أنت مكان واحد لكل ما تحتاجه سيارتك", + "log_in": "تسجيل الدخول", + "send": "إرسال", + "phoneNumber": "رقم الهاتف", + "forgetPasswordQ": "نسيت كلمة المرور؟", + "recover": "استعادة", + "retrivePassword": "استرجع كلمة المرور بإحدى الطرق التالية", + "retriveOnPhone": "سوف نرسل الاختيار إلى رقم هاتفك المحمول المسجل", + "retriveOnEmail": "سوف نرسل الاختيار إلى عنوان بريدك الإلكتروني المسجل", + "enterPhoneForVerfication": "الرجاء إدخال رقم هاتفك وسنرسل لك رمز التحقق", + "welcomeBack": "مرحبًا بعودتك!!!", + "selectYourCountry": "اختر بلدك", + "chooseCountry": "اختر الدوله", + "terms": "بنود الخدمة وخصوصية السياسة", + "profileMsg": "أدخل التفاصيل أدناه وأكمل معلومات الملف الشخصي", + "save": "حفظ", + "insert_otp_code": "ادخل الرمز", + "type_code": "الرجاء كتابة الرمز الذي أرسلناه إلى", + "resend_code": "أعد إرسال الرمز", + "check_code": "التحقق من الشفرة", + "time_will_expire": "إعادة إرسال الرمز بتنسيق", + "sec": "ثانية", + "providers": "الموفرون", + "appointments": "تعيينات", + "home": "بيت", + "ads": "إعلانات", + "settings": "إعدادات", + "view_all": "مشاهدة الكل", + "my_active_Ads": "إعلاناتي النشطة", + "recommended_ads": "الإعلانات الموصى بها", + "upcoming_appointment": "الموعد القادم", + "my_service_providers": "مزودي الخدمة الجدد", + "appointment_details": "تفاصيل الموعد", + "no_city_available": "لا توجد مدينة متاحة لهذا البلد", + "branch_created": "تم إنشاء الفرع بنجاح", + "branch_updated": "تم تحديث الفرع بنجاح", + "branch_deleted": "تم حذف الفرع بنجاح", + "dashboard_main": "لوحة القيادة / الصفحة الرئيسية", + "logo_brand": "الشعار / العلامة التجارية", + "remove": "إزالة", + "no_branch": "لم يتم إضافة فرع حتى الآن", + "login_once": "الرجاء تسجيل الدخول مرة واحدة", + "defineLicenese": "تحميل التراخيص والشهادات", + "description": "وصف", + "attachFile": "أرفق ملف", + "branchLocation": "معلومات الفرع والموقع", + "tapToEdit": "انقر للتعديل", + "myServiceBranches": "فروع خدمتي", + "enter_licence_detail": "الرجاء إدخال تفاصيل السجلات التجارية وإرفاق صور الترخيص", + "country": "بلد", + "city": "مدينة", + "editServices": "تحرير الخدمات", + "maintenance": "صيانة", + "accessories_modifications": "الملحقات والتعديلات", + "my_recent_providers": "مزودي الخدمة الجدد", + "my_active_ads": "إعلاناتي النشطة", + "recommended_Ads": "الإعلانات الموصى بها", + "location": "موقع", + "address": "عنوان", + "branchName": "اسم الفرع", + "branchDescription": "وصف الفرع", + "branchInfo": "معلومات الفرع", + "defineServices": "تحديد الخدمات", + "defineBranches": "تحديد الفروع", + "defineProviders": "تحديد الموفرين", + "closeAccount": "حساب مغلق", + "selectServiceCategory": "حدد فئة الخدمة", + "selectService": "حدد الخدمة", + "selectBranch": "حدد الفرع", + "createBranch": "إنشاء فرع", + "updateBranch": "تحديث فرع", + "branches": "الفروع", + "requests": "الطلبات", + "noBranchFound": "لم يتم العثور على فرع", + "onlyProviderApp": "نأسف هذا التطبيق فقط لمقدمي الخدمات", + "pickAddress": "اختر العنوان", + "pickLocation": "اختر الموقع", + "chooseCity": "اختر المدينه", + "selectAttachment": "اختيار مرفق", + "somethingWrong": "هناك خطأ ما", + "documentsUploaded": "تم ارفاق الملف بنجاح", + "update": "تحديث", + "profileCompleted": "الملف الشخصي مكتمل", + "selectLocationMap": "اختر الموقع", + "licensesAndCertifications": "الرخص و الشهادات", + "completeProfile1": "اكمل الملف الشخصي 1/3", + "completeProfile2": "اكمل الملف الشخصي 2/3", + "completeProfile3": "اكمل الملف الشخصي 3/3", + "provider": "مزود", + "noRequeststoShow": "لا توجد طلبات للعرض", + "myBranches": "فروعي", + "mergeAppointments": "دمج المواعيد", + "addService": "أضف الخدمة", + "selectServicestoAdd": "حدد الخدمات التي تريد إضافتها", + "noServiceFound": "لم يتم العثور على الخدمة", + "selectItems": "اختيار العناصر", + "noItemSelectedYet": "لم يتم تحديد أي عنصر بعد", + "totalAdditionalAmount": "إجمالي المبلغ الإضافي", + "sar": "ريال سعودي", + "cancel": "يلغي", + "add": "يضيف", + "itemsAddedSuccessfully": "تمت إضافة العناصر بنجاح", + "pleaseSelectItems": "يرجى اختيار العناصر", + "totalAmount": "المبلغ الإجمالي", + "searchItems": "البحث عن العناصر", + "addSelectedItems": "إضافة العناصر المحددة", + "collectMoneyBefore": "هل ترغب في جمع المال قبل تقديم الخدمات؟", + "yes": "نعم", + "no": "لا", + "reason": "السبب", + "typeHere": "اكتب هنا...", + "pleaseSelectReason": "يرجى تحديد السبب", + "noAppointmentFound": "لم يتم العثور على مواعيد", + "slotsOverview": "نظرة عامة على الفتحات", + "empty": "فارغ", + "occupied": "محجوز", + "totalSlots": "إجمالي الفتحات", + "selectAppointments": "اختيار المواعيد", + "appointmentMergeSuccessfully": "دمج المواعيد تم بنجاح", + "updateAppointment": "تحديث الموعد", + "addNewService": "إضافة خدمة جديدة", + "waitingPaymentfromtheCustomer": "في انتظار الدفع من العميل", + "appointmentisCompleted": "تم اكتمال الموعد", + "workStart": "بدء العمل", + "payNow": "ادفع الآن", + "arrived": "وصل", + "payLater": "ادفع لاحقًا", + "complete": "اكتمل", + "makeAnOffer": "قدم عرضًا", + "enterAmount": "أدخل المبلغ", + "submit": "إرسال", + "viewChat": "عرض الدردشة", + "requestDetail": "تفاصيل الطلب", + "sendOffer": "إرسال عرض", + "offer": "عرض", + "sendPriceOffer": "إرسال عرض السعر", + "comment": "تعليق", + "sendOTP": "إرسال رمز OTP", + "noUserAddedYet": "لم يتم إضافة مستخدم بعد", + "assignDealerUser": "تعيين مستخدم تاجر", + "createNewUser": "إنشاء مستخدم جديد", + "dealerUser": "مستخدم تاجر", + "setorEditBranchSchedule": "تعيين أو تحرير جدول الفروع", + "addServices": "إضافة خدمات", + "noServiceAddedYet": "لم تتم إضافة خدمات بعد", + "selectDays": "اختيار الأيام", + "addSelectedDays": "إضافة الأيام المحددة", + "select_Services": "اختيار الخدمات", + "searchService": "البحث عن الخدمة", + "addSelectedServices": "إضافة الخدمات المحددة", + "nameofSchedule": "اسم الجدول الزمني", + "startingDate": "تاريخ البدء", + "endDate": "تاريخ الانتهاء", + "offDays": "أيام الراحة", + "shiftStartTime": "وقت بدء الوردية", + "shiftEndTime": "وقت انتهاء الوردية", + "slotsTime": "وقت الفتحات", + "appointmentPerSlot": "موعد لكل فتحة", + "create": "إنشاء", + "pleaseEnterValidScheduleName": "يرجى إدخال اسم جدول صالح", + "pleaseSelectServices": "يرجى اختيار الخدمات", + "pleaseSelectStartDate": "يرجى تحديد تاريخ البدء", + "pleaseSelectEndDate": "يرجى تحديد تاريخ الانتهاء", + "pleaseSelectOffDays": "يرجى تحديد أيام الراحة", + "pleaseSelectStartTime": "يرجى تحديد وقت بدء الوردية", + "pleaseSelectEndTime": "يرجى تحديد وقت انتهاء الوردية", + "pleaseSelectSlotTime": "يرجى تحديد وقت الفتحة", + "pleaseSelectAppointmentPerSlot": "يرجى تحديد موعد لكل فتحة", + "exploreAds": "استكشاف الإعلانات", + "myAds": "إعلاناتي", + "noAppointmentstoShow": "لا توجد مواعيد لعرضها", + "myRecommendedAds": "الإعلانات الموصى بها لي", + "model": "الموديل", + "chooseImageSource": "اختر مصدر الصورة", + "camera": "الكاميرا", + "gallery": "المعرض", + "imageIsDeleted": "تم حذف الصورة", + "myRequests": "طلباتي", + "branchDetail": "تفاصيل الفرع", + "time": "الوقت", + "openMapLocation": "فتح موقع الخريطة", + "providerProfile": "ملف المزود", + "servicesOffer": "الخدمات المقدمة", + "noServicesAvailable": "لا تتوفر خدمات", + "bookAppointment": "حجز موعد", + "allowingHomeService": "السماح بخدمة منزلية", + "homeServiceRange": "نطاق الخدمة المنزلية", + "chargesPerKM": "الرسوم لكل كيلومتر", + "providerDetails": "تفاصيل المزود", + "someDescriptionExperienceandtheirReputation": "بعض الوصف عن المزود وسنوات خبرتهم وسمعتهم", + "availableforAppointment": "متاح للموعد", + "allowingWorkshopService": "السماح بخدمة ورشة العمل", + "serviceAmount": "مبلغ الخدمة", + "youNeedStoragePermissionFiles": "تحتاج إلى منح إذن التخزين لاختيار الملفات.", + "settingDeniedPermanently": "تم رفض هذا الإذن بشكل دائم، يرجى الذهاب إلى الإعدادات والسماح.", + "openAppSetting": "افتح إعدادات التطبيق", + "adDuration": "مدة الإعلان", + "startDate": "تاريخ البدء", + "contactDetails": "تفاصيل الاتصال", + "showyournumbertoBuyers": "هل تريد إظهار رقمك للمشترين؟", + "isNumberRegisteredWhatsApp": "هل هذا الرقم مسجل على واتساب؟", + "selectSpecialServices": "اختر الخدمات الخاصة", + "vehicleDetails": "تفاصيل المركبة", + "vehicleModel": "طراز المركبة", + "vehicleColor": "لون المركبة", + "vehicleCategory": "فئة المركبة", + "vehicleTransmission": "نقل المركبة", + "vehicleCountry": "بلد المركبة", + "vehicleAmount": "مبلغ المركبة", + "vehicleTitle": "عنوان المركبة", + "financeAvailable": "التمويل متاح", + "vehiclePictures": "صور المركبة", + "vehiclePart": "جزء المركبة", + "damagePartPictures": "صور الأجزاء المتضررة", + "vehicleDamagePart": "جزء المركبة المتضرر", + "duration": ":المدة", + "specialServices": "الخدمات الخاصة", + "specialService": "خدمة خاصة", + "adContactDetails": "تفاصيل الاتصال بالإعلان", + "onWhatsAp": "على واتساب", + "reserveAdPriceInfo": "معلومات سعر الإعلان المحجوز", + "addDamagePart": "إضافة جزء متضرر", + "vehicleType": "نوع المركبة", + "vehicleYear": "سنة المركبة", + "vehicleCondition": "حالة المركبة", + "vehicleMileage": "عدد الأميال للمركبة", + "sellerType": "نوع البائع", + "vehicleCity": "مدينة المركبة", + "vehicleVIN": "رقم تعريف المركبة (VIN)", + "warrantyAvailable": "الضمان متاح", + "years": "سنوات", + "vehicleDetail": "تفاصيل المركبة", + "vehicleBrand": "ماركة المركبة", + "vehicleModelYear": "سنة طراز المركبة", + "vehicleSellerType": "نوع بائع المركبة", + "demandAmount": "المبلغ المطلوب", + "warrantyAvailableYears": "الضمان متاح (عدد السنوات)", + "vehicleDescription": "وصف المركبة", + "attachImage": "إرفاق صورة", + "useFingerPrintFaceID": "يرجى استخدام بصمة الإصبع أو معرف الوجه", + "setupTouchID": "يرجى إعداد معرف اللمس", + "reenableTouchID": "يرجى إعادة تمكين معرف اللمس", + "scanFaceIDAuthenticate": "امسح بصمة الإصبع أو معرف الوجه للتحقق", + "AdDeletedSuccessfully": "تم حذف الإعلان بنجاح!", + "yourReservationCancelled": "تم إلغاء حجزك.", + "adDeactivatedSuccessfully": "تم إلغاء تفعيل الإعلان بنجاح!", + "vehicle": { + "selectVehicleType": "يرجى اختيار نوع السيارة", + "selectVehicleModel": "يرجى اختيار طراز السيارة", + "selectVehicleModelYear": "يرجى اختيار سنة طراز السيارة", + "selectVehicleColor": "يرجى اختيار لون السيارة", + "vehicleCondition": "يرجى اختيار حالة السيارة", + "vehicleCategory": "يرجى اختيار فئة السيارة", + "vehicleMileage": "يرجى اختيار عدد أميال السيارة", + "vehicleTransmission": "يرجى اختيار نوع ناقل الحركة", + "vehicleSellerType": "يرجى اختيار نوع بائع السيارة", + "selectAny": "يرجى اختيار أي خيار", + "vehicleCity": "يرجى اختيار مدينة السيارة", + "vehiclePart": "يرجى اختيار جزء السيارة", + "selectValidVehicleType": "يرجى اختيار نوع سيارة صالح" + }, + "selectAppointmentTimeService": "يجب عليك اختيار وقت الموعد للخدمة.", + "error": "خطأ", + "appointmentBookedSuccessfully": "تم حجز موعدك بنجاح", + "appointmentStatusUpdated": "تم تحديث حالة الموعد", + "paymentStatusUpdated": "تم تحديث حالة الدفع", + "selectOneSubService": "يرجى اختيار خدمة فرعية واحدة على الأقل", + "chargesBreakdown": "تفاصيل الرسوم", + "services": "الخدمات", + "homeLocation": "الموقع المنزلي", + "selectAppointmentTime": "يجب عليك اختيار وقت الموعد لكل موعد في الجدول", + "noAppointmentAvailable": "لا توجد مواعيد متاحة للعناصر المحددة", + "changedMind": "لقد غيرت رأيي", + "veryHighPrice": "السعر مرتفع جداً", + "alreadySold": "تم البيع بالفعل", + "otherVar": "أخرى", + "paymentSuccessful": "تم الدفع بنجاح", + "paymentFailed": "فشل الدفع!", + "requestSuccessfullyCreated": "تم إنشاء الطلب بنجاح", + "selectValidRequestType": "يرجى اختيار نوع طلب صالح", + "selectValidBrand": "يرجى اختيار علامة تجارية صالحة", + "selectValidModel": "يرجى اختيار طراز صالح", + "selectValidYear": "يرجى اختيار سنة صالحة", + "selectValidCountry": "يرجى اختيار بلد صالح", + "selectValidCity": "يرجى اختيار مدينة صالحة", + "addValidPrice": "يرجى إضافة سعر صالح", + "addValidDescription": "يرجى إضافة وصف صالح", + "passwordTooShort": "كلمة المرور الخاصة بك قصيرة جدًا", + "passwordAcceptableStrong": "كلمة المرور الخاصة بك مقبولة ولكنها ليست قوية", + "passwordIsStrong": "كلمة المرور الخاصة بك قوية", + "passwordVeryStrong": "كلمة المرور الخاصة بك قوية جدًا", + "selectDuration": "اختر المدة", + "daysVar": "الأيام", + "adCharges": "رسوم الإعلان", + "select": "اختر", + "deleteAdConfirmation": "هل تريد حذف الإعلان؟", + "deleteAdConfirmationMessage": "سيتم حذف إعلانك نهائيًا ولا يمكنك التراجع عن هذا الإجراء", + "mileage": "المسافة المقطوعة", + "transmission": "ناقل الحركة", + "demand": "الطلب", + "adDurationExpired": "انتهت مدة عرض الإعلان الخاص بك", + "bankDetails": "تفاصيل البنك", + "bankName": "اسم البنك", + "iban": "الرقم الدولي للحساب المصرفي (IBAN)", + "rejectionComments": "تعليقات الرفض", + "editAd": "تعديل الإعلان", + "reserveAd": "حجز الإعلان", + "reservationAmount": "مبلغ الحجز", + "belowAmountPayLater": "المبلغ الذي ستدفعه لاحقًا", + "carPrice": "سعر السيارة", + "vatExcluded": "القيمة المضافة غير مشمولة", + "carInsuranceService": "خدمة التأمين على السيارة", + "toBeDecided": "لم يتم اتخاذ القرار بعد", + "registrationCarPlates": "تسجيل ولوحات السيارة", + "homeDeliveryService": "خدمة التوصيل إلى المنزل", + "specialServicechargesInsuranceDeliveryLocation": "سيتم إضافة رسوم خدمة خاصة بناءً على التأمين المطلوب وموقع التسليم", + "estimated": "مقدر", + "servicesReservingAd": "بعض الخدمات إلزامية أثناء حجز الإعلان", + "completeReservation": "إتمام الحجز", + "contact": "اتصال", + "setDateandTime": "تحديد التاريخ والوقت", + "selectOffice": "اختيار المكتب", + "availableSlots": "المواعيد المتاحة", + "bookAndPay": "الحجز والدفع", + "reservationAmounts": "مبالغ الحجز", + "tax": "الضريبة", + "adsFilter": "تصفية الإعلانات", + "searchByCity": "البحث حسب المدينة", + "selectCity": "اختر المدينة", + "searchByBrandName": "البحث حسب اسم العلامة التجارية", + "selectVehicleBrand": "اختر علامة تجارية للسيارة", + "searchByVehicleYear": "البحث حسب سنة السيارة", + "selectYear": "اختر السنة", + "searchByAdOwner": "البحث حسب مالك الإعلان", + "selectOwner": "اختر المالك", + "search": "بحث", + "clearFilters": "مسح التصفية", + "book": "حجز", + "markAsSold": "وضع علامة تم البيع", + "deactivateAd": "إلغاء تفعيل الإعلان", + "doWantDeactivateAd": "هل تريد إلغاء تفعيل هذا الإعلان؟", + "stoptheBuyers": "سنتوقف عن عرض هذا الإعلان للمشترين", + "cancelReservation": "إلغاء الحجز", + "reasonForCancellation": "سبب الإلغاء", + "doWantCancelReservation": "هل تريد إلغاء الحجز؟", + "yourAdVisibletoBuy": "سيتم إلغاء حجز إعلانك وسيكون هذا الإعلان مرئيًا للجميع مرة أخرى للشراء", + "completeDeal": "إتمام الصفقة", + "uploadBankReceipt": "تحميل إيصال البنك", + "notesForAdmin": "ملاحظات للإدارة", + "extendAd": "تمديد الإعلان", + "updateAdDetails": "هل تريد تحديث تفاصيل الإعلان", + "durationExtendingAd": "يمكنك تغيير مدة الإعلان والتفاصيل قبل تمديد الإعلان", + "waitingAdminsResponse": "في انتظار رد الإدارة", + "cancelledByOwner": "ألغيت من قبل المالك", + "cancelledByAdmin": "ألغيت من قبل الإدارة", + "reservationTimeOver": "انتهى وقت الحجز", + "paymentVerified": "تم التحقق من الدفع", + "rejectedFormAdmin": "تم الرفض من قبل الإدارة", + "waitingAdminPost": "في انتظار الإدارة للنشر", + "waitingAdminsApproval": "في انتظار موافقة الإدارة", + "sold": "تم البيع", + "noAdsShow": "لا توجد إعلانات لعرضها", + "damagePartList": "قائمة الأجزاء المتضررة", + "searchPart": "البحث عن جزء", + "addSpecialService": "إضافة خدمة خاصة", + "vehicleVar": "السيارة", + "detailsVar": "التفاصيل", + "damageVar": "الضرر", + "partsVar": "الأجزاء", + "additional": "إضافي", + "review": "مراجعة", + "adVar": "الإعلان", + "updateAd": "تحديث الإعلان", + "createAd": "إنشاء إعلان", + "next": "التالي", + "submitAd": "إرسال الإعلان", + "selectAdType": "اختر نوع الإعلان", + "validUntilSubscriptionExpiration": "صالح حتى انتهاء الاشتراك", + "adsRemainingVar": "الإعلانات المتبقية", + "youLeftAdsGivenSubscription": "لقد بقي لديك 05 من 50 إعلانًا في الاشتراك.", + "updateSubscription": "تحديث الاشتراك", + "workInProgress": "العمل جارٍ", + "visitCompleted": "تمت الزيارة", + "youWantCancelAppointment": "هل تريد إلغاء هذا الموعد؟", + "appointmentCancelledCannotUndoAction": "سيتم إلغاء موعدك ولا يمكنك التراجع عن هذا الإجراء", + "appointment": "الموعد", + "rescheduleAppointment": "إعادة جدولة الموعد", + "payforAppointment": "دفع ثمن الموعد", + "appointmentsFilter": "تصفية المواعيد", + "searchByProvider": "البحث حسب المزود", + "selectProvider": "اختر المزود", + "searchByBranch": "البحث حسب الفرع", + "searchByCategory": "البحث حسب الفئة", + "selectCategory": "اختر الفئة", + "searchByService": "البحث حسب الخدمة", + "selectServices": "اختر الخدمات", + "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": "اللغة", + "mySubscription": "اشتراكاتي", + "subscriptions": "الاشتراكات", + "defineLicenses": "تحديد التراخيص", + "logOut": "تسجيل الخروج", + "customer": "العميل", + "amountVAR": "كمية", + "accept": "قبول", + "requestAlreadyInProgress": "هذا الطلب قيد التقدم بالفعل.", + "acceptOfferConfirmation": "هل تريد قبول هذا العرض؟", + "acceptOfferConfirmationMessage": "سيتم قبول هذا العرض وستدفع المبلغ المطلوب للمشتري في وقت معين وإلا سيتم إلغاء هذا العرض." +}; +static const Map en_US = { + "firstTimeLogIn": "First Time Log In", + "signUp": "Sign Up", + "changeMobile": "Change Mobile", + "notifications": "Notifications", + "general": "General", + "defineLicences": "Define Licences", + "dealershipSettings": "Dealership Settings", + "changePassword": "Change Password", + "retrievePassword": "Retrieve Password", + "changeEmail": "Change Email", + "verify": "Verify", + "verified": "Verified", + "signOut": "Sign Out", + "enterEmail": "Enter Email", + "enterNewEmail": "Enter New Email", + "enterNewPassword": "Enter New Password", + "enterCurrentPassword": "Enter Current Password", + "enterOldPassword": "Enter Old Password", + "confirm": "Confirm", + "completeProfile": "Complete Profile", + "enterNewPhoneNumber": "Enter New Phone Number", + "enterPhoneNumber": "Enter Phone Number", + "continu": "Continue", + "confirmPassword": "Confirm Password", + "createPassword": "Create Password", + "email": "Email", + "firstName": "First Name *", + "surname": "Surname *", + "confirmPass": "Confirm Password *", + "createPass": "Create Password *", + "newPassword": "New Password", + "forgetPassword": "Forget Password", + "forgetPasswordRecover": "Forget Password? Recover", + "editAccount": "Edit Account", + "change": "Change", + "verifyAccount": "Verify Account", + "login": "Log In", + "welcomeMessage": "Welcome Message", + "forgetPass": "Forget Password ?", + "phoneNumberVerified": "Phone Number Verified", + "verifyNewPassword": "Verify New Password", + "EnterPass": "Enter Password ?", + "alreadySigned": " Already Signed Up and Logged In", + "emailChangedSuccessfully": "Email is Changed Successfully", + "passwordIsUpdated": "Password is Updated", + "passwordShouldContains": "Password Should contains Character, Number, Capital and small letters,", + " successfullyRegistered": " Successfully Registered, Please login once,", + "pleaseEnterSamePassword": "Please enter same password", + "firstNameMandatory": "First name is mandatory", + "surnameNameMandatory": "Surname is mandatory", + "passwordNameMandatory": "Password is mandatory", + "enterValidEmail": "Enter Valid Email", + "pleaseAcceptTerms": "Please accept terms", + "emailVerified": "Email is verified successfully", + "selectMethod": "Select Method", + "emailAddress": "Email Address", + "loginSelection": "Login Selection", + "selectCountryCode": "Please select Country Code", + "selectProviderRole": "Please select Provider Role", + "addPhoneNo": "Please add Phone No", + "onlyCustomerApp": "Sorry, Only Customer's can log in this app", + "imageUploaded": "Image is uploaded", + "fileLarger": "File is larger then 1KB", + "account": "Account", + "edit": "EDIT", + "imageDeleted": "Image is Deleted", + "dashboard": "Dashboard/Main Page", + "termsOfService": "By creating an account you agree to our", + "userInformation": "User Information", + "faceRecognition": "Face Recognition", + "fingerPrint": "Finger Print", + "whatsapp": "With Whatsapp", + "SMS": "With SMS", + "selectRole": "Select Role", + "userRoleOrTitle": "User role or title", + "codeSentToEmail": "Code is sent to email", + "number": "Number", + "english": "English", + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "welcomeDes": "You one stop place all your car needs", + "log_in": "Log In", + "send": "Send", + "phoneNumber": "Phone Number", + "forgetPasswordQ": "Forget Password?", + "recover": "Recover", + "retrivePassword": "Retrive password by one of following method", + "retriveOnPhone": "We will send the opt to your registered mobile number", + "retriveOnEmail": "We will send the opt to your registered email address", + "enterPhoneForVerfication": "Please enter your phone number We will send you the verification code", + "welcomeBack": "Welcome Back!!!", + "selectYourCountry": "Select Your Country", + "chooseCountry": "Choose Country", + "terms": "Terms of Service and Privacy Policy", + "profileMsg": "Enter the details below and complete the profile info", + "save": "Save", + "insert_otp_code": "Enter the code", + "type_code": "Please type the code we sent to", + "resend_code": "Resend Code", + "check_code": "Check Code", + "time_will_expire": "Resend code in", + "sec": "sec", + "providers": "Providers", + "appointments": "Appointments", + "home": "Home", + "ads": "Ads", + "settings": "Settings", + "view_all": "view all", + "my_active_Ads": "My Active Ads", + "recommended_ads": "Recommended Ads", + "upcoming_appointment": "Upcoming Appointment", + "my_service_providers": "My Recent Service Providers", + "appointment_details": "Appointment Details", + "no_city_available": "No City Available for this country", + "branch_created": "Branch is successfully created", + "branch_updated": "Branch is successfully Updated", + "branch_deleted": "Branch is successfully Deleted", + "dashboard_main": "Dashboard/Main Page", + "logo_brand": "Logo/Brand", + "remove": "Remove", + "no_branch": "No Branch Added Yet", + "login_once": "Please login once", + "defineLicenese": "Upload Licenses and Certificates", + "description": "Description", + "attachFile": "Attach File", + "branchLocation": "Branch info and Location", + "tapToEdit": "Tap to edit", + "myServiceBranches": "My Service Branches", + "enter_licence_detail": "Please enter the detail for commercial records and attach the license images", + "country": "Country", + "city": "City", + "editServices": "Edit Services", + "maintenance": "Maintenance", + "accessories_modifications": "Accessories and Modifications", + "my_recent_providers": "My Recent Service Providers", + "my_active_ads": "My Active Ads", + "recommended_Ads": "Recommended Ads", + "select_services": "Select services you want", + "location": "Location", + "address": "Address", + "branchName": "Branch Name", + "branchDescription": "Branch Description", + "branchInfo": "Branch Info", + "defineServices": "Define Services", + "defineBranches": "Define Branches", + "defineProviders": "Define Providers", + "closeAccount": "Close Account", + "selectServiceCategory": "Select Service Category", + "selectService": "Select Service", + "selectBranch": "Select Branch", + "createBranch": "Create Branch", + "updateBranch": "Update Branch", + "branches": "Branches", + "requests": "Requests", + "noBranchFound": "No Branch Found", + "pickAddress": "Pick Address", + "pickLocation": "Pick Location", + "chooseCity": "Select City", + "selectAttachment": "Select Attachment", + "somethingWrong": "Something went wrong", + "documentsUploaded": "Documents uploaded successfully", + "update": "Update", + "profileCompleted": "Profile is Completed", + "selectLocationMap": "Select Location Map", + "licensesAndCertifications": "licenses & certifications", + "completeProfile1": "Complete Profile 1/3", + "completeProfile2": "Complete Profile 2/3", + "completeProfile3": "Complete Profile 3/3", + "provider": "Provider", + "noRequeststoShow": "No Requests to Show", + "myBranches": "My Branches", + "mergeAppointments": "Merge Appointments", + "addService": "Add Service", + "selectServicestoAdd": "Select services you want to add", + "noServiceFound": "No Service Found", + "selectItems": "Select Items", + "noItemSelectedYet": "No Item Selected Yet", + "totalAdditionalAmount": "Total Additional Amount", + "sar": "SAR", + "cancel": "Cancel", + "add": "Add", + "itemsAddedSuccessfully": "Items are added Successfully", + "pleaseSelectItems": "Please select items", + "totalAmount": "Total Amount", + "searchItems": "Search Items", + "addSelectedItems": "Add Selected Items", + "collectMoneyBefore": "Do you want to collect the money before providing services?", + "yes": "Yes", + "no": "No", + "reason": "Reason", + "typeHere": "Type Here...", + "pleaseSelectReason": "Please Select Reason", + "noAppointmentFound": "No Appointment Found", + "slotsOverview": "Slots Overview", + "empty": "Empty", + "occupied": "Occupied", + "totalSlots": "Total Slots", + "selectAppointments": "Select Appointments", + "appointmentMergeSuccessfully": "Appointment Merge is Successfully done", + "updateAppointment": "Update Appointment", + "addNewService": "Add New Service", + "waitingPaymentfromtheCustomer": "Waiting for the payment from the customer", + "appointmentisCompleted": "Appointment is completed", + "workStart": "Work Start", + "payNow": "Pay Now", + "arrived": "Arrived", + "payLater": "Pay Later", + "complete": "Complete", + "makeAnOffer": "Make an offer", + "enterAmount": "Enter amount", + "submit": "Submit", + "viewChat": "View Chat", + "requestDetail": "Request Detail", + "sendOffer": "Send Offer", + "offer": "Offer", + "sendPriceOffer": "Send Price Offer", + "comment": "Comment", + "sendOTP": "Send OTP", + "noUserAddedYet": "No User Added Yet", + "assignDealerUser": "Assign Dealer User", + "createNewUser": "Create New User", + "dealerUser": "Dealer User", + "setorEditBranchSchedule": "Set or Edit Branch Schedule", + "addServices": "Add Services", + "noServiceAddedYet": "No Service Added Yet", + "selectDays": "Select Days", + "addSelectedDays": "Add Selected Days", + "select_Services": "Select Services", + "searchService": "Search Service", + "addSelectedServices": "Add Selected Services", + "nameofSchedule": "Name of Schedule", + "startingDate": "Starting Date", + "endDate": "End Date", + "offDays": "Off Days", + "shiftStartTime": "Shift Start Time", + "shiftEndTime": "Shift End Time", + "slotsTime": "Slots Time", + "appointmentPerSlot": "Appointment Per Slot", + "create": "Create", + "pleaseEnterValidScheduleName": "Please enter valid schedule Name", + "pleaseSelectServices": "Please select Services", + "pleaseSelectStartDate": "Please select start date", + "pleaseSelectEndDate": "Please select end date", + "pleaseSelectOffDays": "Please Select off Days", + "pleaseSelectStartTime": "Please select start time", + "pleaseSelectEndTime": "Please select end time", + "pleaseSelectSlotTime": "Please select slot time", + "pleaseSelectAppointmentPerSlot": "Please select appointment per slot", + "exploreAds": "Explore Ads", + "myAds": "My Ads", + "noAppointmentstoShow": "No Appointments to show", + "myRecommendedAds": "My Recommended Ads", + "model": "Model", + "chooseImageSource": "Choose image source", + "camera": "Camera", + "gallery": "Gallery", + "imageIsDeleted": "Image is Deleted", + "myRequests": "My Requests", + "branchDetail": "Branch Detail", + "time": "Time", + "openMapLocation": "Open Map Location", + "providerProfile": "Provider Profile", + "servicesOffer": "Services Offer", + "noServicesAvailable": "No Services Available", + "bookAppointment": "Book Appointment", + "allowingHomeService": "Allowing home service", + "homeServiceRange": "Home service range", + "chargesPerKM": "Charges per KM", + "providerDetails": "Provider Details", + "someDescriptionExperienceandtheirReputation": "Some description about the provider and their years of experience and their reputation", + "availableforAppointment": "Available for appointment", + "allowingWorkshopService": "Allowing Workshop service", + "serviceAmount": "Service Amount", + "youNeedStoragePermissionFiles.": "You need to give storage permission to select files.", + "settingDeniedPermanently": "This permission was denied permanently, Please go to settings and allow. ", + "openAppSetting": "Open App Setting", + "adDuration": "Ad Duration", + "startDate": "Start Date", + "contactDetails": "Contact Details", + "showyournumbertoBuyers": "Do you want to show your number to the buyers?", + "isNumberRegisteredWhatsApp": "Is this number registered on WhatsApp?", + "selectSpecialServices": "Select Special Services", + "vehicleDetails": "Vehicle Details", + "vehicleModel": "Vehicle Model", + "vehicleColor": "Vehicle Color", + "vehicleCategory": "Vehicle Category", + "vehicleTransmission": "Vehicle Transmission", + "vehicleCountry": "Vehicle Country", + "vehicleAmount": "Vehicle Amount", + "vehicleTitle": "Vehicle Title", + "financeAvailable": "Finance Available", + "vehiclePictures": "Vehicle Pictures", + "vehiclePart": "Vehicle Part", + "damagePartPictures": "Damage Part Pictures", + "vehicleDamagePart": "Vehicle Damage Part", + "duration": "Duration:", + "specialServices": "Special Services", + "specialService": "Special Service", + "adContactDetails": "Ad Contact Details", + "onWhatsAp": "On WhatsAp", + "reserveAdPriceInfo": "Reserve Ad Price Info", + "addDamagePart": "Add Damage Part", + "vehicleType": "Vehicle Type", + "vehicleYear": "Vehicle Year", + "vehicleCondition": "Vehicle Condition", + "vehicleMileage": "Vehicle Mileage", + "sellerType": "Seller Type", + "vehicleCity": "Vehicle City", + "vehicleVIN": "Vehicle VIN", + "warrantyAvailable": "Warranty Available", + "years": "Years", + "vehicleDetail": "Vehicle Detail", + "vehicleBrand": "Vehicle Brand", + "vehicleModelYear": "Vehicle Model Year", + "vehicleSellerType": "Vehicle Seller Type", + "demandAmount": "Demand Amount", + "warrantyAvailableYears": "Warranty Available (No. of Years)", + "vehicleDescription": "Vehicle Description", + "attachImage": "Attach Image", + "useFingerPrintFaceID": "Please use your fingerprint or face ID", + "setupTouchID": "Please set up your Touch ID", + "reenableTouchID": "Please reenable your Touch ID", + "scanFaceIDAuthenticate": "Scan your fingerprint or face ID to authenticate", + "adDeletedSuccessfully": "Ad has been deleted successfully!", + "yourReservationCancelled": "Your reservation has been cancelled.", + "adDeactivatedSuccessfully": "Ad has been deactivated successfully!", + "vehicle": { + "selectVehicleType": "Please select vehicle type", + "selectVehicleModel": "Please select vehicle model", + "selectVehicleModelYear": "Please select vehicle model year", + "selectVehicleColor": "Please select vehicle color", + "vehicleCondition": "Please select vehicle condition", + "vehicleCategory": "Please select vehicle category", + "vehicleMileage": "Please select vehicle Mileage", + "vehicleTransmission": "Please select vehicle transmission", + "vehicleSellerType": "Please select vehicle seller type", + "selectAny": "Please select any", + "vehicleCity": "Please select vehicle city", + "vehiclePart": "Please select vehicle part", + "selectValidVehicleType": "Please select valid Vehicle Type" + }, + "selectAppointmentTimeService": "You must select appointment time the service.", + "error": "Error", + "appointmentBookedSuccessfully": "Your appointment has been booked successfully", + "appointmentStatusUpdated": "Appointment Status Updated", + "paymentStatusUpdated": "Payment Status Updated", + "selectOneSubService": "Please select at least one sub service", + "chargesBreakdown": "Charges Breakdown", + "services": "Services", + "homeLocation": "Home Location", + "selectAppointmentTime": "You must select appointment time for each schedule's appointment", + "noAppointmentAvailable": "There are no available appointments for selected Items", + "changedMind": "I have changed my mind", + "veryHighPrice": "Very High Price", + "alreadySold": "Already Sold", + "otherVar": "Other", + "paymentSuccessful": "Payment Successful", + "paymentFailed": "Payment Failed!", + "requestSuccessfullyCreated": "Request Successfully Created", + "selectValidRequestType": "Please select valid Request Type", + "selectValidBrand": "Please select valid Brand", + "selectValidModel": "Please select valid Model", + "selectValidYear": "Please select valid Year", + "selectValidCountry": "Please select valid Country", + "selectValidCity": "Please select valid City", + "addValidPrice": "Please add valid Price", + "addValidDescription": "Please add valid Description", + "passwordTooShort": "Your password is too short", + "passwordAcceptableStrong": "Your password is acceptable but not strong", + "passwordIsStrong": "Your password is strong", + "passwordVeryStrong": "Your password is very strong", + "onlyProviderApp": "Sorry, Only Customer's can log in this app", + "selectDuration": "Select Duration", + "daysVar": "Days", + "adCharges": "Ad Charges", + "select": "Select", + "deleteAdConfirmation": "Do you want to delete the ad?", + "deleteAdConfirmationMessage": "Your ad will be permanently deleted and you cannot undo this action", + "mileage": "mileage", + "transmission": "Transmission", + "demand": "Demand", + "adDurationExpired": "Your Ad Duration time is over", + "bankDetails": "Bank Details", + "bankName": "Bank Name", + "iban": "IBAN", + "rejectionComments": "Rejection Comments", + "editAd": "Edit Ad", + "reserveAd": "Reserve Ad", + "reservationAmount": "Reservation Amount", + "belowAmountPayLater": "Below Amount that you will pay later", + "carPrice": "Car Price", + "vatExcluded": "VAT Excluded", + "carInsuranceService": "Car insurance Service", + "toBeDecided": "To be Decided", + "registrationCarPlates": "Registration & Car Plates", + "homeDeliveryService": "Home Delivery Service", + "specialServicechargesInsuranceDeliveryLocation": "Special service charges will be added based on desired insurance and delivery Location", + "estimated": "Estimated", + "servicesReservingAd": "Some services are mandatory while reserving Ad", + "completeReservation": "Complete Reservation", + "contact": "Contact", + "setDateandTime": "Set Date and Time", + "selectOffice": "Select Office", + "availableSlots": "Available Slots", + "bookAndPay": "Book and Pay", + "reservationAmounts": "Reservation Amounts", + "tax": "Tax", + "adsFilter": "Ads Filter", + "searchByCity": "Search By City", + "selectCity": "Select City", + "searchByBrandName": "Search By Brand Name", + "selectVehicleBrand": "Select Vehicle Brand", + "searchByVehicleYear": "Search By Vehicle Year", + "selectYear": "Select Year", + "searchByAdOwner": "Search By Ad Owner", + "selectOwner": "Select Owner", + "search": "Search", + "clearFilters": "Clear Filters", + "book": "Book", + "markAsSold": "Mark As Sold", + "deactivateAd": "Deactivate Ad", + "doWantDeactivateAd": "Do you want to the Deactivate this Ad?", + "stoptheBuyers": "We will stop showing this ad to the buyers", + "cancelReservation": "Cancel Reservation", + "reasonForCancellation": "Reason for Cancellation", + "doWantCancelReservation": "Do you want to cancel the reservation", + "yourAdVisibletoBuy.": "Your ad reservation will be cancelled and this ad will be again visible to everyone to buy", + "completeDeal": "Complete Deal", + "uploadBankReceipt": "Upload Bank Receipt", + "notesForAdmin": "Notes For Admin", + "extendAd": "Extend Ad", + "updateAdDetails": "Do you want to update the Ad Details", + "durationExtendingAd": "You can change the ad duration and details before extending the ad", + "waitingAdminsResponse": "Waiting for Admins Response", + "cancelledByOwner": "Cancelled by Owner", + "cancelledByAdmin": "Cancelled by Admin", + "reservationTimeOver": "Reservation Time Over", + "paymentVerified": "Payment Verified", + "rejectedFormAdmin": "Rejected form Admin", + "waitingAdminPost": "Waiting for admin to post", + "waitingAdminsApproval": "Waiting for Admins Approval", + "sold": "Sold", + "noAdsShow": "No Ads to show", + "damagePartList": "Damage Part List", + "searchPart": "Search Part", + "addSpecialService": "Add Special Service", + "vehicleVar": "Vehicle", + "detailsVar": "Details", + "damageVar": "Damage", + "partsVar": "Parts", + "additional": "Additional", + "review": "Review", + "adVar": "Ad", + "updateAd": "Update Ad", + "createAd": "Create Ad", + "next": "Next", + "submitAd": "Submit Ad", + "selectAdType": "Select Ad Type", + "validUntilSubscriptionExpiration": "Valid Until Subscription Expiration", + "adsRemaining ": "Ads Remaining", + "youLeftAdsGivenSubscription": "You have left with 05 out of 50 ads given in the subscription.", + "updateSubscription": "Update Subscription", + "workInProgress": "Work In Progress", + "visitCompleted": "Visit Completed", + "youWantCancelAppointment": "Do you want to cancel this appointment?", + "appointmentCancelledCannotUndoAction": "Your appointment will be cancelled and you cannot undo this action.", + "appointment": "Appointment", + "rescheduleAppointment": "Reschedule Appointment", + "payforAppointment": "Pay for Appointment", + "appointmentsFilter": "Appointments Filter", + "searchByProvider": "Search By Provider", + "selectProvider": "Select Provider", + "searchByBranch": "Search By Branch", + "searchByCategory": "Search By Category", + "selectCategory": "Select Category", + "searchByService": "Search By Service", + "selectServices": "Select Services", + "modifyPackage": "Modify Package", + "schedule": "Schedule", + "serviceLocation": "Service Location:", + "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", + "subscriptions": "Subscriptions", + "defineLicenses": "Define Licenses", + "logOut": "Log Out", + "customer": "Customer", + "accept": "Accept", + "amountVAR": "Amount", + "requestAlreadyInProgress": "This request is already in progress.", + "acceptOfferConfirmation": "Do you want to accept this offer?", + "acceptOfferConfirmationMessage": "This offer will be accepted and you will pay the requested amount to the buyer in given time or else this offer will be cancelled." +}; +static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 66ce054..ef84d47 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -545,8 +545,10 @@ abstract class LocaleKeys { static const defineLicenses = 'defineLicenses'; static const logOut = 'logOut'; static const customer = 'customer'; - static const accept = 'accept'; static const amountVAR = 'amountVAR'; + static const accept = 'accept'; static const requestAlreadyInProgress = 'requestAlreadyInProgress'; + static const acceptOfferConfirmation = 'acceptOfferConfirmation'; + static const acceptOfferConfirmationMessage = 'acceptOfferConfirmationMessage'; } diff --git a/lib/main.dart b/lib/main.dart index 67dd452..1049c48 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,94 +10,54 @@ import 'package:provider/single_child_widget.dart'; import 'package:sizer/sizer.dart'; //testing push -final navigatorKey = GlobalKey(); Logger logger = Logger( // printer: PrettyPrinter(lineLength: 0, methodCount: 0,), ); - -class MyHttpOverrides extends HttpOverrides { - @override - HttpClient createHttpClient(SecurityContext? context) { - return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true; - } -} - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - await EasyLocalization.ensureInitialized(); - // AppState().setPostParamsInitConfig(); - HttpOverrides.global = MyHttpOverrides(); - - runApp( - EasyLocalization( - supportedLocales: const [ - Locale('en', 'US'), - Locale('ar', 'SA'), - ], - path: 'resources', - // assetLoader: const CodegenLoader(), - child: MultiProvider( - providers: const [ - // ChangeNotifierProvider( - // create: (_) => LoginProviderModel(), - // ), - ], - child: const MyApp(), - ), - ), - ); -} - -// todo terminal command to genertate translation files -// flutter pub run easy_localization:generate --source-dir ./assets/langs -// todo terminal command to genertate translation keys -// flutter pub run easy_localization:generate --source-dir ./assets/langs -f keys -o locale_keys.g.dart -// command to generate languages data from json - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return LayoutBuilder(builder: (context, constraints) { - return Sizer( - builder: ( - BuildContext context, - Orientation orientation, - DeviceType deviceType, - ) { - List> delegates = context.localizationDelegates; - // AppState().setPostParamsModel( - // PostParamsModel( - // languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, - // ), - // ); - return MaterialApp( - // key: navigatorKey, - navigatorKey: navigatorKey, - theme: AppTheme.getTheme( - isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar", - ), - debugShowCheckedModeBanner: false, - localizationsDelegates: delegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - ); - }, - ); - }); - } -} - -// class MyApp extends StatelessWidget { -// MyApp({super.key}) { -// AppDependencies.addDependencies(); -// AppState = Injector.appInstance.get(); -// // AppState.setPostParamsInitConfig(); +// +// class MyHttpOverrides extends HttpOverrides { +// @override +// HttpClient createHttpClient(SecurityContext? context) { +// return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true; // } +// } +// +// Future main() async { +// WidgetsFlutterBinding.ensureInitialized(); +// +// await EasyLocalization.ensureInitialized(); +// // AppState().setPostParamsInitConfig(); +// HttpOverrides.global = MyHttpOverrides(); +// +// runApp( +// EasyLocalization( +// supportedLocales: const [ +// Locale('en', 'US'), +// Locale('ar', 'SA'), +// ], +// path: 'resources', +// // assetLoader: const CodegenLoader(), +// child: MultiProvider( +// providers: const [ +// // ChangeNotifierProvider( +// // create: (_) => LoginProviderModel(), +// // ), +// ], +// child: const MyApp(), +// ), +// ), +// ); +// } +// +// // todo terminal command to genertate translation files +// // flutter pub run easy_localization:generate --source-dir ./assets/langs +// // todo terminal command to genertate translation keys +// // flutter pub run easy_localization:generate --source-dir ./assets/langs -f keys -o locale_keys.g.dart +// // command to generate languages data from json +// +// class MyApp extends StatelessWidget { +// const MyApp({super.key}); // // @override // Widget build(BuildContext context) { @@ -108,7 +68,6 @@ class MyApp extends StatelessWidget { // Orientation orientation, // DeviceType deviceType, // ) { -// SizeConfig().init(constraints, orientation); // List> delegates = context.localizationDelegates; // // AppState().setPostParamsModel( // // PostParamsModel( @@ -117,19 +76,58 @@ class MyApp extends StatelessWidget { // // ); // return MaterialApp( // // key: navigatorKey, -// navigatorKey: navigatorKey, // theme: AppTheme.getTheme( -// EasyLocalization.of(context)?.locale.languageCode == "ar", +// isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar", // ), // debugShowCheckedModeBanner: false, // localizationsDelegates: delegates, // supportedLocales: context.supportedLocales, // locale: context.locale, -// initialRoute: AppRoutes.initialPage, -// routes: AppRoutes.routes, // ); // }, // ); // }); // } // } +// +// // class MyApp extends StatelessWidget { +// // MyApp({super.key}) { +// // AppDependencies.addDependencies(); +// // AppState = Injector.appInstance.get(); +// // // AppState.setPostParamsInitConfig(); +// // } +// // +// // @override +// // Widget build(BuildContext context) { +// // return LayoutBuilder(builder: (context, constraints) { +// // return Sizer( +// // builder: ( +// // BuildContext context, +// // Orientation orientation, +// // DeviceType deviceType, +// // ) { +// // SizeConfig().init(constraints, orientation); +// // List> delegates = context.localizationDelegates; +// // // AppState().setPostParamsModel( +// // // PostParamsModel( +// // // languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, +// // // ), +// // // ); +// // return MaterialApp( +// // // key: navigatorKey, +// // navigatorKey: navigatorKey, +// // theme: AppTheme.getTheme( +// // EasyLocalization.of(context)?.locale.languageCode == "ar", +// // ), +// // debugShowCheckedModeBanner: false, +// // localizationsDelegates: delegates, +// // supportedLocales: context.supportedLocales, +// // locale: context.locale, +// // initialRoute: AppRoutes.initialPage, +// // routes: AppRoutes.routes, +// // ); +// // }, +// // ); +// // }); +// // } +// // } diff --git a/lib/models/advertisment_models/ad_details_model.dart b/lib/models/advertisment_models/ad_details_model.dart index 322a226..0b1b304 100644 --- a/lib/models/advertisment_models/ad_details_model.dart +++ b/lib/models/advertisment_models/ad_details_model.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; +import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/utils/enums.dart'; class AdDetailsModel { @@ -44,46 +45,49 @@ class AdDetailsModel { String? phoneNo; String? whatsAppNo; CreatedByRoleEnum? createdByRoleEnum; - - AdDetailsModel( - {this.id, - this.startdate, - this.enddate, - this.vehicle, - this.specialservice, - // this.reserved, - this.statusID, - this.statuslabel, - this.adsDurationPrice, - this.adsDurationDiscount, - this.adsDurationDiscountPrice, - this.comment, - this.active, - this.isPaid, - this.isSubscription, - this.isVerified, - this.netPrice, - this.specialServiceTotalPrice, - this.taxPrice, - this.totalPrice, - this.userID, - this.vehiclePostingID, - this.qrCodePath, - this.isCustomerAcknowledged, - this.createdByRole, - this.totalViews, - this.createdOn, - this.priceExcludingDiscount, - this.reservePrice, - this.isMCHandled, - this.adPostStatus, - this.adReserveStatus, - this.isMyAd, - this.isReservedByMe, - this.phoneNo, - this.whatsAppNo, - this.createdByRoleEnum, - this.modifiedOn}); + List? adMessages; + + AdDetailsModel({ + this.id, + this.startdate, + this.enddate, + this.vehicle, + this.specialservice, + // this.reserved, + this.statusID, + this.statuslabel, + this.adsDurationPrice, + this.adsDurationDiscount, + this.adsDurationDiscountPrice, + this.comment, + this.active, + this.isPaid, + this.isSubscription, + this.isVerified, + this.netPrice, + this.specialServiceTotalPrice, + this.taxPrice, + this.totalPrice, + this.userID, + this.vehiclePostingID, + this.qrCodePath, + this.isCustomerAcknowledged, + this.createdByRole, + this.totalViews, + this.createdOn, + this.priceExcludingDiscount, + this.reservePrice, + this.isMCHandled, + this.adPostStatus, + this.adReserveStatus, + this.isMyAd, + this.isReservedByMe, + this.phoneNo, + this.whatsAppNo, + this.createdByRoleEnum, + this.modifiedOn, + this.adMessages, + }); int getRandomValue({required int min, required int max}) { Random random = Random(); @@ -157,7 +161,7 @@ class Vehicle { ModelYear? modelyear; Condition? sellertype; Condition? transmission; - Duration? duration; + AdsDuration? duration; List? image; List? damagereport; String? vehicleDescription; @@ -211,7 +215,7 @@ class Vehicle { modelyear = json['modelyear'] != null ? ModelYear.fromJson(json['modelyear']) : null; sellertype = json['sellertype'] != null ? Condition.fromJson(json['sellertype']) : null; transmission = json['transmission'] != null ? Condition.fromJson(json['transmission']) : null; - duration = json['duration'] != null ? Duration.fromJson(json['duration']) : null; + duration = json['duration'] != null ? AdsDuration.fromJson(json['duration']) : null; if (json['image'] != null) { image = []; json['image'].forEach((v) { @@ -326,16 +330,16 @@ class ModelYear { } } -class Duration { +class AdsDuration { int? id; String? label; int? days; double? price; ModelYear? country; - Duration({this.id, this.label, this.days, this.price, this.country}); + AdsDuration({this.id, this.label, this.days, this.price, this.country}); - Duration.fromJson(Map json) { + AdsDuration.fromJson(Map json) { id = json['id']; label = json['label']; days = json['days']; diff --git a/lib/models/requests_models/provider_offers_model.dart b/lib/models/requests_models/provider_offers_model.dart index 8c2cd3b..d566b9b 100644 --- a/lib/models/requests_models/provider_offers_model.dart +++ b/lib/models/requests_models/provider_offers_model.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:mc_common_app/main.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; class ProviderOffersModel { @@ -66,7 +67,7 @@ class ServiceProvidersOffers { ServiceProvidersOffers.fromJson(Map json) { providerId = json['providerID']; - providerUserId = json['providerUserId'] ?? "c680271c-b2a7-4ecf-7e95-08db545aec1b"; //TODO Remove this when parameter is added in backend + providerUserId = json['providerUserID']; name = json['name']; mobileNo = json['mobileNo']; email = json['email']; @@ -74,4 +75,9 @@ class ServiceProvidersOffers { offerCount = json['offerCount']; chatMessages = []; } + + @override + String toString() { + return 'ServiceProvidersOffers{providerUserId: $providerUserId, providerId: $providerId, name: $name, mobileNo: $mobileNo, email: $email, companyName: $companyName, offerCount: $offerCount, chatMessages: $chatMessages}'; + } } diff --git a/lib/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index 0c8aa8e..f7e6ef7 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -4,7 +4,7 @@ import 'dart:developer'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/main.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index a581c3d..d8fa683 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -3,7 +3,7 @@ import 'dart:developer'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; diff --git a/lib/repositories/branch_repo.dart b/lib/repositories/branch_repo.dart index 5de2eee..566de9c 100644 --- a/lib/repositories/branch_repo.dart +++ b/lib/repositories/branch_repo.dart @@ -3,7 +3,7 @@ import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; diff --git a/lib/repositories/chat_repo.dart b/lib/repositories/chat_repo.dart index 42e64b6..e731c67 100644 --- a/lib/repositories/chat_repo.dart +++ b/lib/repositories/chat_repo.dart @@ -4,7 +4,7 @@ import 'package:http/io_client.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/main.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index 0e7a8df..5580913 100644 --- a/lib/repositories/common_repo.dart +++ b/lib/repositories/common_repo.dart @@ -1,7 +1,7 @@ import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart'; import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; diff --git a/lib/repositories/items_repo.dart b/lib/repositories/items_repo.dart index fc8faee..9688c75 100644 --- a/lib/repositories/items_repo.dart +++ b/lib/repositories/items_repo.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/services_models/item_model.dart'; diff --git a/lib/repositories/payments_repo.dart b/lib/repositories/payments_repo.dart index 7f72e8b..4ffa1fe 100644 --- a/lib/repositories/payments_repo.dart +++ b/lib/repositories/payments_repo.dart @@ -1,7 +1,7 @@ import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart'; diff --git a/lib/repositories/request_repo.dart b/lib/repositories/request_repo.dart index eb9aaad..16d7a93 100644 --- a/lib/repositories/request_repo.dart +++ b/lib/repositories/request_repo.dart @@ -1,7 +1,7 @@ import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/requests_models/offers_model.dart'; @@ -18,7 +18,7 @@ abstract class RequestRepo { Future> getRequests(Map postParams); - Future updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId}); + Future updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}); } class RequestRepoImp implements RequestRepo { @@ -93,10 +93,11 @@ class RequestRepoImp implements RequestRepo { } @override - Future updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId}) async { + Future updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}) async { var queryParameters = { "requestOfferId": requestOfferId.toString(), "offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(), + "comments": comments, }; GenericRespModel genericRespModel = await apiClient.postJsonForObject( (json) => GenericRespModel.fromJson(json), diff --git a/lib/repositories/schedule_repo.dart b/lib/repositories/schedule_repo.dart index 59b0629..09be713 100644 --- a/lib/repositories/schedule_repo.dart +++ b/lib/repositories/schedule_repo.dart @@ -4,7 +4,7 @@ import 'package:mc_common_app/models/provider_branches_models/profile/services.d import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; abstract class ScheduleRepo { Future getAllServices(String branchId); diff --git a/lib/repositories/subscription_repo.dart b/lib/repositories/subscription_repo.dart index fd2b037..606d2a1 100644 --- a/lib/repositories/subscription_repo.dart +++ b/lib/repositories/subscription_repo.dart @@ -1,7 +1,7 @@ import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; diff --git a/lib/repositories/user_repo.dart b/lib/repositories/user_repo.dart index f5656ed..7856020 100644 --- a/lib/repositories/user_repo.dart +++ b/lib/repositories/user_repo.dart @@ -6,7 +6,7 @@ import 'package:http/http.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/user_models/basic_otp.dart'; import 'package:mc_common_app/models/user_models/change_email.dart'; diff --git a/lib/services/firebase_service.dart b/lib/services/firebase_service.dart new file mode 100644 index 0000000..8320373 --- /dev/null +++ b/lib/services/firebase_service.dart @@ -0,0 +1,103 @@ +import 'dart:io'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/main.dart'; +import 'package:permission_handler/permission_handler.dart'; + +abstract class FirebaseMessagingService { + Future getFirebaseToken(); + + Future initializeNotifications(); +} + +class FirebaseMessagingServiceImp implements FirebaseMessagingService { + final FlutterLocalNotificationsPlugin flutterLocalNotifications; + final FirebaseMessaging firebaseMessaging; + + FirebaseMessagingServiceImp({required this.firebaseMessaging, required this.flutterLocalNotifications}); + + @override + Future getFirebaseToken() async => await firebaseMessaging.getToken() ?? ""; + + Future requestPermissions() async { + if (Platform.isIOS) { + await flutterLocalNotifications.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + } else if (Platform.isAndroid) { + AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotifications.resolvePlatformSpecificImplementation(); + bool? granted = await androidImplementation?.requestNotificationsPermission(); + if (granted == false) { + await Permission.notification.request(); + } + } + } + + @override + Future initializeNotifications() async { + await requestPermissions(); + AppState().setDeviceToken = await getFirebaseToken(); + await Permission.notification.isDenied.then((bool value) { + if (value) { + Permission.notification.request(); + } + }); + + // initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project + const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('ic_launcher'); + final DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings(onDidReceiveLocalNotification: _onDidReceiveLocalNotification); + final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsDarwin); + await flutterLocalNotifications.initialize(initializationSettings, onDidReceiveNotificationResponse: (notificationResponse) {}); + + RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); + + if (initialMessage != null) _handleNotification(initialMessage); + + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + if (message.notification != null) _handleNotification(message); + }); + + FirebaseMessaging.onMessageOpenedApp.listen(_handleNotification); + + FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); + + FirebaseMessaging.instance.onTokenRefresh.listen((String token) async { + AppState().setDeviceToken = token; + }); + } + + void _onDidReceiveLocalNotification(int id, String? title, String? body, String? payload) async { + logger.i(body); + } + + void _handleNotification(RemoteMessage message) async { + logger.i(message.notification!.title); + logger.i(message.notification!.body); + + displayNotification(title: message.notification!.title ?? '', body: message.notification!.body ?? ''); + } + + Future displayNotification({required String title, required String body}) async { + const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( + "0", + 'mowater', + channelDescription: 'mowater_notifications', + importance: Importance.max, + priority: Priority.high, + ticker: 'ticker', + ); + + const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails(threadIdentifier: 'thread_id'); + const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails, iOS: iOSPlatformChannelSpecifics); + await flutterLocalNotifications.show(0, title, body, notificationDetails, payload: 'item x'); + } +} + +@pragma('vm:entry-point') +Future backgroundMessageHandler(RemoteMessage message) async { + await Firebase.initializeApp(); +} diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 230d81f..52d3d48 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter/cupertino.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/dependency_injection.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; @@ -1808,6 +1808,13 @@ class AdVM extends BaseVM { int ifSpecialServiceAlreadyThere(int id) { return specialServiceCards.indexWhere((element) => element.serviceSelectedId!.selectedId == id); } + + void onMessagesButtonPressed({required BuildContext context, required AdDetailsModel adDetailsModel}) { + ChatViewArgumentsForAd chatViewArgumentsForAd = ChatViewArgumentsForAd(adDetailsModel: adDetailsModel); + + ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.ads, chatViewArgumentsForAd: chatViewArgumentsForAd); + navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments); + } } // Edit Work End Amir diff --git a/lib/view_models/chat_view_model.dart b/lib/view_models/chat_view_model.dart index 212d4d3..8e4b8d2 100644 --- a/lib/view_models/chat_view_model.dart +++ b/lib/view_models/chat_view_model.dart @@ -8,6 +8,7 @@ import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/main.dart'; +import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'; @@ -46,6 +47,23 @@ class ChatVM extends ChangeNotifier { notifyListeners(); } + bool isUserOnChatScreen = false; + + final ScrollController scrollController = ScrollController(); + + void scrollChatDown() { + if (!isUserOnChatScreen) { + return; + } + + logger.i(scrollController.position.maxScrollExtent); + scrollController.animateTo( + scrollController.position.maxScrollExtent + 200, // for the text field + duration: const Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + ); + } + List offerRejectModelList = [ OfferRequestCommentModel( index: 0, @@ -69,10 +87,17 @@ class ChatVM extends ChangeNotifier { ), ]; + OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel( + index: 3, + isSelected: true, + title: LocaleKeys.otherVar.tr(), + ); + void updateSelectionInOfferRejectModelList(int index) { for (var value in offerRejectModelList) { value.isSelected = false; } + selectedOfferRequestCommentModel = offerRejectModelList[index]; offerRejectModelList[index].isSelected = true; notifyListeners(); } @@ -89,6 +114,9 @@ class ChatVM extends ChangeNotifier { //REJECTING OFFER bool isRejectOfferButtonValidated() { + if (selectedOfferRequestCommentModel.index != offerRejectModelList.length - 1) { + return true; + } bool isValidated = true; if (rejectOfferDescription.isEmpty) { rejectOfferDescriptionError = GlobalConsts.descriptionError; @@ -102,35 +130,32 @@ class ChatVM extends ChangeNotifier { return isValidated; } - Future onNewMessageReceived({required List messages, required BuildContext context, bool isMyOwnOffer = false}) async { + Future onNewMessageReceived({required List messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async { if (AppState().currentAppType == AppType.customer) { for (var msg in messages) { - int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID); // TODO : NEED TO BE CHECKED + int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID); if (providerIndex != -1) { serviceProviderOffersList[providerIndex].chatMessages!.add(msg); + scrollChatDown(); } } - - //providerUserId } else { for (var msg in messages) { + logger.i(msg); // Where we need to call this function for saving a message in chat we will use receiverUserID and in those cases where received ID is null , it means it is a signal R call int providerIndex = -1; if (isMyOwnOffer) { - providerIndex = context.read().myFilteredRequests.indexWhere( - (element) => element.customerUserID == msg.receiverUserID, - ); + providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.receiverUserID && element.id == msg.requestID)); } else { - providerIndex = context.read().myFilteredRequests.indexWhere( - (element) => element.customerUserID == msg.senderUserID, - ); + providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.senderUserID && element.id == msg.requestID)); } + log("providerIndex: $providerIndex"); if (providerIndex != -1) { - context.read().addChatMessagesInRequestsModel(msg: msg, index: providerIndex); + requestsVM.addChatMessagesInRequestsModel(msg: msg, index: providerIndex); + scrollChatDown(); } } } - notifyListeners(); } @@ -139,16 +164,28 @@ class ChatVM extends ChangeNotifier { try { hubConnection = await chatRepo.getHubConnection(); await hubConnection!.start(); - hubConnection!.on("ReceiveMessageRequestOffer", (List? arguments) { + hubConnection!.on(SignalrConsts.receiveMessageRequestOffer, (List? arguments) { if (arguments == null || arguments.isEmpty) return; List chat = []; for (var message in arguments) { final chatMessage = ChatMessageModel.fromJson(message as Map); chat.add(chatMessage); } - onNewMessageReceived(messages: chat, context: context); - logger.i("I received ping : ${arguments.toString()}"); + onNewMessageReceived(messages: chat, requestsVM: context.read()); + logger.i(arguments); + Utils.showToast(arguments.toString()); }); + + hubConnection!.onclose((exception) { + logger.i("onClose: ${exception.toString()}"); + buildHubConnection(context); + }); + hubConnection!.onreconnecting((exception) => () { + logger.i("onReconnecting: ${exception.toString()}"); + }); + hubConnection!.onreconnected((connectionId) => () { + logger.i("onReconnected: ${connectionId.toString()}"); + }); } catch (e) { logger.i("Error: ${e.toString()}"); } @@ -157,7 +194,7 @@ class ChatVM extends ChangeNotifier { } } - Future onSendMessageForRequestOffer({ + Future onOfferSendForRequest({ required String receiverId, required ChatMessageTypeEnum chatMessageType, required String message, @@ -166,12 +203,13 @@ class ChatVM extends ChangeNotifier { required BuildContext context, }) async { if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { + logger.i("Hub Not Connected!!"); await buildHubConnection(context); } if (hubConnection!.state == HubConnectionState.connected) { final providerId = AppState().getUser.data!.userInfo!.providerId; hubConnection!.invoke( - "SendMessageRequestOffer", + SignalrConsts.sendMessageRequestOffer, args: [ { "ReceiverUserID": receiverId, @@ -196,12 +234,14 @@ class ChatVM extends ChangeNotifier { } logger.i({ + "ID": "", //here should be req offer ID "ReceiverUserID": receiverId, "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "ChatText": message, "RequestID": requestId, "ReqOfferID": 0, "ReqOffer": { + "ID": "", "RequestID": requestId, "Price": double.parse(offerPrice), "ServiceProviderID": AppState().getUser.data!.userInfo!.providerId, @@ -212,7 +252,7 @@ class ChatVM extends ChangeNotifier { return true; } - Future onTextMessageSend({ + Future onTextMessageSendForRequest({ required String receiverId, required ChatMessageTypeEnum chatMessageType, required String message, @@ -223,6 +263,8 @@ class ChatVM extends ChangeNotifier { if (message.isEmpty) return false; if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { + logger.i("Hub Not Connected!!"); + await buildHubConnection(context); } if (hubConnection!.state == HubConnectionState.connected) { @@ -236,10 +278,11 @@ class ChatVM extends ChangeNotifier { "ChatText": message, "RequestID": requestId, "ReqOfferID": latestOfferId, + // "ReqOffer": {} })); hubConnection!.invoke( - "SendMessageRequestOffer", + SignalrConsts.sendMessageRequestOffer, args: [ { "ReceiverUserID": receiverId, @@ -248,6 +291,7 @@ class ChatVM extends ChangeNotifier { "ChatText": message, "RequestID": requestId, "ReqOfferID": latestOfferId, + // "ReqOffer": {} } ], ).catchError((e) { @@ -273,7 +317,8 @@ class ChatVM extends ChangeNotifier { serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel); } } else { - int providerIndex = context.read().myFilteredRequests.indexWhere((element) => element.customerUserID == receiverId); + int providerIndex = context.read().myFilteredRequests.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId)); + log("providerIndex2:$providerIndex"); if (providerIndex != -1) { context.read().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex); } @@ -340,7 +385,7 @@ class ChatVM extends ChangeNotifier { int providerId = AppState().getUser.data!.userInfo!.providerId!; Utils.showLoading(context); List chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId); - context.read().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex); + context.read().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context); Utils.hideLoading(context); } catch (e) { logger.i(e.toString()); @@ -349,11 +394,10 @@ class ChatVM extends ChangeNotifier { } } - Future onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId}) async { + Future onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId, required String comments}) async { try { - Utils.showLoading(context); - GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId); - Utils.hideLoading(context); + GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId, comments: comments); + Utils.showToast(genericRespModel.message.toString()); return genericRespModel.messageStatus == 1 ? reqOfferId : -1; } catch (e) { logger.i(e.toString()); @@ -362,4 +406,131 @@ class ChatVM extends ChangeNotifier { return -1; } } + + Future onSendMessageForActionOnRequestOffer({ + required String receiverId, + required ChatMessageTypeEnum chatMessageType, + required String comments, + required int requestId, + required int serviceProviderID, + required int requestOfferID, + required String offerPrice, + required RequestOfferStatusEnum requestOfferStatusEnum, + required BuildContext context, + }) async { + if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { + logger.i("Hub Not Connected!!"); + + await buildHubConnection(context); + } + if (hubConnection!.state == HubConnectionState.connected) { + hubConnection!.invoke( + SignalrConsts.sendMessageRequestOffer, + args: [ + { + "ReceiverUserID": receiverId, + "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), + "ChatText": comments, + "RequestID": requestId, + "ReqOfferID": requestOfferID, + "ReqOffer": { + "ID": requestOfferID, + "RequestID": requestId, + "Price": double.parse(offerPrice), + "ServiceProviderID": serviceProviderID, + "OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(), + "Comment": comments, + }, + } + ], + ).catchError((e) { + logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}"); + Utils.showToast(e.toString()); + return false; + }); + } + + logger.i({ + "ReceiverUserID": receiverId, + "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), + "ChatText": comments, + "RequestID": requestId, + "ReqOfferID": 0, + "ReqOffer": { + "ID": requestOfferID, + "RequestID": requestId, + "Price": double.parse(offerPrice), + "ServiceProviderID": serviceProviderID, + "OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(), + "Comment": comments, + }, + }); + return true; + } + + // =================== Ads ====================== + + Future onTextMessageSendForAds({ + required String receiverId, + required ChatMessageTypeEnum chatMessageType, + required String message, + required AdDetailsModel adDetailsModel, + required BuildContext context, + }) async { + if (message.isEmpty) return false; + + if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { + logger.i("Hub Not Connected!!"); + await buildHubConnection(context); + } + + if (hubConnection!.state == HubConnectionState.connected) { + final userId = AppState().getUser.data!.userInfo!.userId.toString(); + final name = AppState().getUser.data!.userInfo!.firstName.toString(); + + hubConnection!.invoke( + SignalrConsts.sendMessageAds, + args: [ + { + "ReceiverUserID": receiverId, + "SenderUserID": userId, + "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), + "ChatText": message, + "AdsID": adDetailsModel.id, + } + ], + ).catchError((e) { + logger.i("error in invoking SendMessage: ${e.toString()}"); + Utils.showToast(e.toString()); + return false; + }); + + ChatMessageModel chatMessageModel = ChatMessageModel( + messageType: chatMessageType.getIdFromChatMessageTypeEnum(), + chatText: message, + isMyMessage: true, + requestID: 0, + senderName: name, + senderUserID: userId, + chatMessageTypeEnum: ChatMessageTypeEnum.freeText, + receiverUserID: receiverId, + ); + + if (AppState().currentAppType == AppType.customer) { + + + + + + + } else { + + + + + } + return true; + } + return false; + } } diff --git a/lib/view_models/dashboard_view_model_customer.dart b/lib/view_models/dashboard_view_model_customer.dart index 513bbe0..2bebc2a 100644 --- a/lib/view_models/dashboard_view_model_customer.dart +++ b/lib/view_models/dashboard_view_model_customer.dart @@ -1,13 +1,23 @@ import 'dart:io'; import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/main.dart'; +import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/models/user_models/image_response.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; +import 'package:mc_common_app/services/firebase_service.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:mc_common_app/view_models/chat_view_model.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; +import 'package:provider/provider.dart'; class DashboardVmCustomer extends BaseVM { final CommonAppServices commonServices; @@ -19,7 +29,8 @@ class DashboardVmCustomer extends BaseVM { int selectedNavbarBarIndex = 2; - void onNavbarTapped(int index) { + void onNavbarTapped(int index) async { + print(AppState().getDeviceToken); selectedNavbarBarIndex = index; notifyListeners(); } @@ -49,6 +60,56 @@ class DashboardVmCustomer extends BaseVM { } } + onInitState(BuildContext context) async { + Future.wait([ + context.read().populateRequestsFilterList(), + context.read().populateAppointmentsFilterList(), + context.read().populateBranchesFilterList(), + context.read().populateAdsFilterList(), + ]); + } + + Future onRefresh(BuildContext context) async { + AdVM adVM = Provider.of(context, listen: false); + AppointmentsVM appointmentsVM = Provider.of(context, listen: false); + RequestsVM requestsVM = Provider.of(context, listen: false); + ChatVM chatVM = Provider.of(context, listen: false); + if (appointmentsVM.myAppointments.isEmpty) { + await appointmentsVM.getMyAppointments(); + } + + if (appointmentsVM.nearbyBranches.isEmpty) { + await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches! + } + + if (adVM.myAds.isEmpty) { + await adVM.getMyAds(); + } + if (adVM.exploreAds.isEmpty) { + await adVM.getExploreAds(); + } + if (requestsVM.myRequests.isEmpty) { + await requestsVM.getRequests(appType: AppType.customer); + } + + if (adVM.vehicleTypes.isEmpty) { + await adVM.getVehicleTypes(); + } + + if (adVM.vehicleAdsDurations.isEmpty) { + await adVM.getVehicleAdsDuration(); + } + + await chatVM.buildHubConnection(context); + adVM.updateVehicleAdDurationId( + SelectionModel( + selectedId: adVM.vehicleAdsDurations.first.id ?? 0, + selectedOption: "${adVM.vehicleAdsDurations.first.days} Days", + itemPrice: adVM.vehicleAdsDurations.first.price!.toInt().toString(), + ), + ); + } + Future updateUserImage(String image) async { return await userRepo.updateUserImage(image); } diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 757ab73..6ef229d 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -83,13 +83,22 @@ class RequestsVM extends BaseVM { } addChatMessagesInRequestsModel({required ChatMessageModel msg, required int index}) { + log("msg: $msg"); + log("index: $index"); myFilteredRequests[index].chatMessages.add(msg); notifyListeners(); } - overwriteChatMessagesInRequestsModel({required List messages, required int index}) { + overwriteChatMessagesInRequestsModel({required List messages, required int index, required BuildContext context}) { myFilteredRequests[index].chatMessages.clear(); myFilteredRequests[index].chatMessages = messages; + if (myFilteredRequests[index].chatMessages.isNotEmpty) { + for (var message in myFilteredRequests[index].chatMessages) { + if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) { + context.read().updateLatestOfferId(message.reqOfferID ?? 0); + } + } + } notifyListeners(); } @@ -100,7 +109,6 @@ class RequestsVM extends BaseVM { } requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList(); - notifyListeners(); } @@ -420,7 +428,7 @@ class RequestsVM extends BaseVM { }) async { if (isSendOfferValidated()) { final chatVM = context.read(); - bool status = await chatVM.onSendMessageForRequestOffer( + bool status = await chatVM.onOfferSendForRequest( receiverId: receiverId, chatMessageType: ChatMessageTypeEnum.offer, message: message, @@ -432,7 +440,7 @@ class RequestsVM extends BaseVM { if (status) { final senderName = AppState().getUser.data!.userInfo!.firstName; final senderId = AppState().getUser.data!.userInfo!.userId; - // resetSendOfferBottomSheet(); + resetSendOfferBottomSheet(); Navigator.pop(context); ChatMessageModel chatMessageModel = ChatMessageModel( isMyMessage: true, @@ -452,9 +460,10 @@ class RequestsVM extends BaseVM { comment: message, offerStatusText: "", )); - context.read().onNewMessageReceived(messages: [chatMessageModel], context: context, isMyOwnOffer: true); + context.read().onNewMessageReceived(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true); + if (!isFromChatScreen) { - ChatViewArguments chatViewArguments = ChatViewArguments( + ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest( chatTypeEnum: ChatTypeEnum.requestOffer, requestId: requestModel.id, receiverId: requestModel.customerID, @@ -462,6 +471,8 @@ class RequestsVM extends BaseVM { requestIndex: requestIndex, providerIndex: -1, ); + + ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest); navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments); } } diff --git a/lib/views/advertisement/ads_detail_view.dart b/lib/views/advertisement/ads_detail_view.dart index 49756ed..8999417 100644 --- a/lib/views/advertisement/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view.dart @@ -42,8 +42,11 @@ class AdsDetailView extends StatefulWidget { } class _AdsDetailViewState extends State { + late AdVM adVM; + @override void initState() { + adVM = context.read(); scheduleMicrotask(() { onAdDetailsLoaded(); }); @@ -53,12 +56,11 @@ class _AdsDetailViewState extends State { Future onAdDetailsLoaded() async { context.read().updateCurrentAdId(id: widget.adDetails.id!); if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus == AdPostStatus.reserved)) { - await context.read().getAdBankingAccountInfo(adId: widget.adDetails.id!); + await adVM.getAdBankingAccountInfo(adId: widget.adDetails.id!); } } void deleteAdBottomSheet(BuildContext context) { - AdVM adVM = context.read(); return actionConfirmationBottomSheet( context: context, title: LocaleKeys.deleteAdConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), @@ -99,17 +101,14 @@ class _AdsDetailViewState extends State { isRemoveBackButton: false, isDrawerEnabled: false, actions: [ - ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) + ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active) ? IconButton( icon: const Icon(Icons.delete_outline, color: MyColors.redColor), onPressed: () { return deleteAdBottomSheet(context); }, ) - : IconButton( - icon: const Icon(Icons.chat_outlined, color: Colors.black), - onPressed: () {}, - )) + : IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails))) .toContainer( margin: const EdgeInsets.fromLTRB(0, 8, 21, 8), paddingAll: 0, @@ -154,7 +153,7 @@ class _AdsDetailViewState extends State { children: [ Row( children: [ - (LocaleKeys.model.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.model.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), "${widget.adDetails.vehicle!.modelyear!.label}".toText( fontSize: 14, isBold: true, @@ -169,7 +168,7 @@ class _AdsDetailViewState extends State { children: [ Row( children: [ - (LocaleKeys.mileage.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.mileage.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), "${widget.adDetails.vehicle!.mileage!.mileageEnd}Km".toText( fontSize: 14, isBold: true, @@ -183,7 +182,7 @@ class _AdsDetailViewState extends State { ), Row( children: [ - (LocaleKeys.transmission.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.transmission.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), "${widget.adDetails.vehicle!.transmission!.label}".toText( fontSize: 14, isBold: true, @@ -191,14 +190,14 @@ class _AdsDetailViewState extends State { ], ), 8.height, - (LocaleKeys.description.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.description.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), "${widget.adDetails.vehicle!.vehicleDescription}".toText( fontSize: 14, isBold: true, ), if (widget.adDetails.isMyAd ?? false) ...[ 8.height, - (LocaleKeys.demand.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.demand.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -238,7 +237,7 @@ class _AdsDetailViewState extends State { // ), Row( children: [ - (LocaleKeys.bankName.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.bankName.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), (adVM.adsBankDetailsModel!.bankName ?? "").toText( fontSize: 14, isBold: true, @@ -247,7 +246,7 @@ class _AdsDetailViewState extends State { ), Row( children: [ - (LocaleKeys.iban.tr() + ": ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + ("${LocaleKeys.iban.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), (adVM.adsBankDetailsModel!.iban ?? "").toText( fontSize: 14, isBold: true, @@ -278,10 +277,10 @@ class _AdsDetailViewState extends State { ], ).onPress(() async { Utils.showLoading(context); - await context.read().getVehicleTypes(); - await context.read().getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1); + await adVM.getVehicleTypes(); + await adVM.getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1); Utils.hideLoading(context); - context.read().onEditUpdateAdPressed(context, widget.adDetails); + adVM.onEditUpdateAdPressed(context, widget.adDetails); }), ], ).paddingOnly(bottom: 5), @@ -842,7 +841,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { isFilled: false, borderColor: MyColors.darkPrimaryColor, maxHeight: 55, - title: (LocaleKeys.book.tr() + " ${photoSpecialServiceModel.name}"), + title: ("${LocaleKeys.book.tr()} ${photoSpecialServiceModel.name}"), txtColor: MyColors.darkPrimaryColor, onPressed: () { onBookPhotographyServiceClicked(context, adDetailsModel: adDetailsModel); diff --git a/lib/views/chat/chat_view.dart b/lib/views/chat/chat_view.dart index ff754b1..f91b0fd 100644 --- a/lib/views/chat/chat_view.dart +++ b/lib/views/chat/chat_view.dart @@ -1,5 +1,4 @@ import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; @@ -10,7 +9,9 @@ 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'; +import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/chat_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; @@ -22,13 +23,48 @@ 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 { +class ChatView extends StatefulWidget { final ChatViewArguments chatViewArguments; const ChatView({super.key, required this.chatViewArguments}); + @override + State createState() => _ChatViewState(); +} + +class _ChatViewState extends State { + late ChatVM chatVM; + + late ChatTypeEnum chatTypeEnum; + ChatViewArgumentsForRequest? chatViewArgumentsForRequest; + ChatViewArgumentsForAd? chatViewArgumentsForAd; + + @override + void initState() { + chatTypeEnum = widget.chatViewArguments.chatTypeEnum; + if (chatTypeEnum == ChatTypeEnum.ads) { + chatViewArgumentsForAd = widget.chatViewArguments.chatViewArgumentsForAd; + } else if (chatTypeEnum == ChatTypeEnum.requestOffer) { + chatViewArgumentsForRequest = widget.chatViewArguments.chatViewArgumentsForRequest; + } + chatVM = context.read(); + chatVM.isUserOnChatScreen = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (chatVM.scrollController.hasClients) { + chatVM.scrollChatDown(); + } + }); + super.initState(); + } + + @override + void dispose() { + chatVM.isUserOnChatScreen = false; + super.dispose(); + } + Future buildSendOfferBottomSheet(BuildContext context) { - RequestModel requestDetail = chatViewArguments.requestModel!; + RequestModel requestDetail = chatViewArgumentsForRequest!.requestModel!; return showModalBottomSheet( context: context, isScrollControlled: true, @@ -51,6 +87,7 @@ class ChatView extends StatelessWidget { errorValue: requestsVM.offerPriceError, keyboardType: TextInputType.number, hint: LocaleKeys.enterAmount.tr(), + numbersOnly: true, onChanged: (v) => requestsVM.updateOfferPrice(v), ), 12.height, @@ -75,7 +112,7 @@ class ChatView extends StatelessWidget { requestId: requestDetail.id, offerPrice: requestsVM.offerPrice, requestModel: requestDetail, - requestIndex: chatViewArguments.requestIndex, + requestIndex: chatViewArgumentsForRequest!.requestIndex, isFromChatScreen: true, ); }, @@ -90,20 +127,44 @@ class ChatView extends StatelessWidget { ); } + Future onTextMessageSend() async { + bool status = false; + if (chatTypeEnum == ChatTypeEnum.requestOffer) { + status = await chatVM.onTextMessageSendForRequest( + context: context, + receiverId: chatViewArgumentsForRequest!.receiverId, + message: chatVM.chatMessageText, + requestId: chatViewArgumentsForRequest!.requestId ?? 0, + offerPrice: "0.0", + chatMessageType: ChatMessageTypeEnum.freeText, + ); + } else if (chatTypeEnum == ChatTypeEnum.ads) { + } else {} + return status; + } + @override Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar(title: LocaleKeys.chat.tr()), body: Consumer2(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; - return chatMessages == null - ? Center(child: LocaleKeys.noRequestsShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor)) - : Column( - children: [ - Expanded( - child: ListView.separated( + List chatMessages = []; + if (chatTypeEnum == ChatTypeEnum.ads) { + chatMessages = chatViewArgumentsForAd!.adDetailsModel!.adMessages ?? []; + } else if (chatTypeEnum == ChatTypeEnum.requestOffer) { + if (AppState().currentAppType == AppType.customer) { + chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? []; + } else { + chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages; + } + } + return Column( + children: [ + Expanded( + child: chatMessages.isEmpty + ? Center(child: LocaleKeys.noRequestsShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor)) + : ListView.separated( + controller: chatVM.scrollController, itemCount: chatMessages.length, separatorBuilder: (BuildContext context, int index) => 20.height, itemBuilder: (BuildContext context, int index) { @@ -111,73 +172,73 @@ class ChatView extends StatelessWidget { return ChatMessageCustomWidget(chatMessageModel: chatMessageModel); }, ).horPaddingMain(), - ), - 10.height, - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (requestVM.currentSelectedRequest!.requestStatus == RequestStatus.inProgress) ...[ - Center( - child: LocaleKeys.requestAlreadyInProgress.tr().toText( - textAlign: TextAlign.center, - color: MyColors.lightTextColor, - fontSize: 14, - ), - ).paddingAll(15) - ] else ...[ - if (AppState().currentAppType == AppType.provider) ...[ - Expanded( - flex: 1, - child: const Icon( - Icons.local_offer_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress( - () async { - buildSendOfferBottomSheet(context); - }, - ), - ), - ], - Expanded( - flex: 8, - child: TxtField( - value: chatVM.chatMessageText, - hint: LocaleKeys.typeMessageHere.tr(), - keyboardType: TextInputType.text, - isNeedBorder: false, - onChanged: (v) => chatVM.updateChatMessageText(v), - ), + ), + 10.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (chatTypeEnum == ChatTypeEnum.requestOffer && requestVM.currentSelectedRequest!.requestStatus == RequestStatus.inProgress) ...[ + Center( + child: LocaleKeys.requestAlreadyInProgress.tr().toText( + textAlign: TextAlign.center, + color: MyColors.lightTextColor, + fontSize: 14, ), - Expanded( - flex: 1, - child: const Icon( - Icons.send_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress( - () async { - log("chatViewArguments.requestId:${chatViewArguments.requestId}"); - final status = await chatVM.onTextMessageSend( - context: context, - receiverId: chatViewArguments.receiverId, - message: chatVM.chatMessageText, - requestId: chatViewArguments.requestId ?? 0, - offerPrice: "0.0", - chatMessageType: ChatMessageTypeEnum.freeText, - ); + ).paddingAll(15) + ] else ...[ + if (AppState().currentAppType == AppType.provider && chatTypeEnum == ChatTypeEnum.requestOffer) ...[ + Expanded( + flex: 1, + child: const Icon( + Icons.local_offer_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress( + () async { + buildSendOfferBottomSheet(context); + }, + ), + ), + ], + Expanded( + flex: 8, + child: TxtField( + value: chatVM.chatMessageText, + hint: LocaleKeys.typeMessageHere.tr(), + keyboardType: TextInputType.text, + isNeedBorder: false, + onChanged: (v) => chatVM.updateChatMessageText(v), + ), + ), + Expanded( + flex: 1, + child: const Icon( + Icons.send_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress( + () async { + final status = await chatVM.onTextMessageSendForRequest( + context: context, + receiverId: chatViewArgumentsForRequest!.receiverId, + message: chatVM.chatMessageText, + requestId: chatViewArgumentsForRequest!.requestId ?? 0, + offerPrice: "0.0", + chatMessageType: ChatMessageTypeEnum.freeText, + ); - if (status) { - chatVM.clearChatMessageText(); - } - }, - ), - ), - ], - ], - ).toContainer(isShadowEnabled: true), + if (status) { + chatVM.scrollChatDown(); + chatVM.clearChatMessageText(); + } + }, + ), + ), ], - ); + ], + ).toContainer(isShadowEnabled: true), + ], + ); }), // body: ); @@ -194,7 +255,7 @@ class ChatMessageCustomWidget extends StatefulWidget { } class _ChatMessageCustomWidgetState extends State { - Future buildRejectOfferBottomSheet() { + Future buildRejectOfferBottomSheet({required ChatMessageModel chatMessageModel}) { return showModalBottomSheet( context: context, isScrollControlled: true, @@ -228,21 +289,55 @@ class _ChatMessageCustomWidgetState extends State { ); }, ), - 12.height, - TxtField( - maxLines: 5, - value: chatVM.rejectOfferDescription, - errorValue: chatVM.rejectOfferDescriptionError, - keyboardType: TextInputType.text, - hint: LocaleKeys.description.tr(), - onChanged: (v) => chatVM.updateRejectOfferDescription(v), - ), + if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) ...[ + // comparing if the "other" is selected + 12.height, + TxtField( + maxLines: 5, + value: chatVM.rejectOfferDescription, + errorValue: chatVM.rejectOfferDescriptionError, + keyboardType: TextInputType.text, + hint: LocaleKeys.description.tr(), + onChanged: (v) => chatVM.updateRejectOfferDescription(v), + ), + ], ], ), 25.height, ShowFillButton( title: LocaleKeys.submit.tr(), - onPressed: () {}, + onPressed: () async { + String comments = ""; + if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) //Other + { + comments = chatVM.rejectOfferDescription; + } else { + comments = chatVM.selectedOfferRequestCommentModel.title ?? ""; + } + if (!chatVM.isRejectOfferButtonValidated()) { + return; + } + Navigator.pop(context); + bool status = await context.read().onSendMessageForActionOnRequestOffer( + receiverId: chatMessageModel.receiverUserID ?? "", + chatMessageType: ChatMessageTypeEnum.offer, + comments: comments, + requestId: chatMessageModel.reqOffer!.requestID ?? -1, + serviceProviderID: chatMessageModel.serviceProviderID ?? 0, + requestOfferID: chatMessageModel.reqOffer!.id ?? -1, + offerPrice: chatMessageModel.reqOffer!.price.toString(), + requestOfferStatusEnum: RequestOfferStatusEnum.rejected, + context: context, + ); + + if (status) { + chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.rejected; + setState(() {}); + // Navigator.pop(context); + Utils.showToast("Offer Rejected"); + // navigateReplaceWithName(context, AppRoutes.dashboard); + } + }, maxWidth: double.infinity, ), 19.height, @@ -254,6 +349,65 @@ class _ChatMessageCustomWidgetState extends State { ); } + void offerAcceptConfirmationBottomSheet({required ChatMessageModel chatMessageModel}) { + return actionConfirmationBottomSheet( + context: context, + title: LocaleKeys.acceptOfferConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + subtitle: LocaleKeys.acceptOfferConfirmationMessage.tr(), + actionButtonYes: Expanded( + child: ShowFillButton( + maxHeight: 55, + title: LocaleKeys.yes.tr(), + fontSize: 15, + onPressed: () async { + log("ServiceProviderID: ${chatMessageModel.toString()}"); + Navigator.pop(context); + // int status = await context.read().onActionOfferTapped( + // context: context, + // requestOfferStatusEnum: RequestOfferStatusEnum.accepted, + // reqOfferId: chatMessageModel.reqOfferID ?? -1, + // comments: GlobalConsts.acceptingThisOffer, + // ); + + bool status = await context.read().onSendMessageForActionOnRequestOffer( + receiverId: chatMessageModel.receiverUserID ?? "", + chatMessageType: ChatMessageTypeEnum.offer, + comments: GlobalConsts.acceptingThisOffer, + requestId: chatMessageModel.reqOffer!.requestID ?? -1, + serviceProviderID: chatMessageModel.serviceProviderID ?? 0, + requestOfferID: chatMessageModel.reqOffer!.id ?? -1, + offerPrice: chatMessageModel.reqOffer!.price.toString(), + requestOfferStatusEnum: RequestOfferStatusEnum.accepted, + context: context, + ); + + if (status) { + chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted; + setState(() {}); + // Navigator.pop(context); + Utils.showToast("Offer Accepted"); + + // navigateReplaceWithName(context, AppRoutes.dashboard); + } + }, + ), + ), + actionButtonNo: Expanded( + child: ShowFillButton( + maxHeight: 55, + isFilled: false, + borderColor: MyColors.darkPrimaryColor, + title: LocaleKeys.no.tr(), + txtColor: MyColors.darkPrimaryColor, + fontSize: 15, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ); + } + Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) { final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer; @@ -281,19 +435,8 @@ class _ChatMessageCustomWidgetState extends State { fontSize: 9, borderColor: MyColors.greenColor, isFilled: false, - onPressed: () async { - int status = await context.read().onActionOfferTapped( - context: context, - requestOfferStatusEnum: RequestOfferStatusEnum.accepted, - reqOfferId: chatMessageModel.reqOfferID ?? -1, - ); - - if (status != -1) { - if (chatMessageModel.reqOfferID == status) { - chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted; - setState(() {}); - } - } + onPressed: () { + offerAcceptConfirmationBottomSheet(chatMessageModel: chatMessageModel); }, backgroundColor: MyColors.white, txtColor: MyColors.greenColor, @@ -310,7 +453,7 @@ class _ChatMessageCustomWidgetState extends State { txtColor: MyColors.redColor, fontSize: 9, onPressed: () async { - buildRejectOfferBottomSheet(); + buildRejectOfferBottomSheet(chatMessageModel: chatMessageModel); }, ), ) diff --git a/lib/views/requests/offer_list_page.dart b/lib/views/requests/offer_list_page.dart index 72a8a2f..5ce13c7 100644 --- a/lib/views/requests/offer_list_page.dart +++ b/lib/views/requests/offer_list_page.dart @@ -88,7 +88,7 @@ class OfferListPage extends StatelessWidget { ), ], ).onPress(() async { - ChatViewArguments chatViewArguments = ChatViewArguments( + ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest( chatTypeEnum: ChatTypeEnum.requestOffer, receiverId: "${offersModel.providerUserId}", senderId: AppState().getUser.data!.userInfo!.userId.toString(), @@ -97,6 +97,8 @@ class OfferListPage extends StatelessWidget { requestIndex: -1, // This will be only send in case of provider ); + ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest); + final chatVM = context.read(); await chatVM diff --git a/lib/views/requests/widget/request_item.dart b/lib/views/requests/widget/request_item.dart index a863b3f..1c0bb96 100644 --- a/lib/views/requests/widget/request_item.dart +++ b/lib/views/requests/widget/request_item.dart @@ -124,7 +124,6 @@ class RequestItem extends StatelessWidget { navigateWithName(context, AppRoutes.requestsDetailPage, arguments: requestDetailPageArguments); } else { ChatVM chatVM = context.read(); - await chatVM.getOffersFromProvidersByRequest(requestId: request.id, context: context); OfferListPageArguments offerListPageArguments = OfferListPageArguments(serviceProviderOffers: chatVM.serviceProviderOffersList, requestId: request.id); navigateWithName(context, AppRoutes.offersListPage, arguments: offerListPageArguments); diff --git a/lib/views/user/login_method_selection_page.dart b/lib/views/user/login_method_selection_page.dart index 76b1d28..fdc5df3 100644 --- a/lib/views/user/login_method_selection_page.dart +++ b/lib/views/user/login_method_selection_page.dart @@ -5,7 +5,7 @@ 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/dependency_injection.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; @@ -33,7 +33,6 @@ class _LoginMethodSelectionPageState extends State { Widget build(BuildContext context) { UserVM userVM = context.read(); AppState appState = injector.get(); - print("current: ${appState.currentAppType}"); return Scaffold( appBar: CustomAppBar(isRemoveBackButton: true, title: LocaleKeys.log_in.tr()), body: Container( diff --git a/lib/views/user/login_with_password_page.dart b/lib/views/user/login_with_password_page.dart index c6f1bb3..e7f2658 100644 --- a/lib/views/user/login_with_password_page.dart +++ b/lib/views/user/login_with_password_page.dart @@ -49,10 +49,10 @@ class _LoginWithPasswordState extends State { userVM = Provider.of(context, listen: false); context.read().getAvailBio(); if (AppState().currentAppType == AppType.provider) { - // phoneNum = "966530896018"; - // password = "Amir@1234"; - phoneNum = "966569755630"; - password = "Amir12345@"; + phoneNum = "966530896018"; + password = "Amir@1234"; + // phoneNum = "966569755630"; + // password = "Amir12345@"; } getCountryList(); diff --git a/lib/views/user/register_provider_page.dart b/lib/views/user/register_provider_page.dart index ca78f1c..eb59608 100644 --- a/lib/views/user/register_provider_page.dart +++ b/lib/views/user/register_provider_page.dart @@ -1,4 +1,4 @@ -import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/config/dependency_injection.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'; diff --git a/lib/views/user/register_selection_page.dart b/lib/views/user/register_selection_page.dart index 5301054..bf139e9 100644 --- a/lib/views/user/register_selection_page.dart +++ b/lib/views/user/register_selection_page.dart @@ -2,7 +2,7 @@ import 'dart:async'; 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/dependency_injection.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart index 37304a7..5a76c36 100644 --- a/lib/widgets/txt_field.dart +++ b/lib/widgets/txt_field.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; @@ -33,6 +34,7 @@ class TxtField extends StatelessWidget { bool isBackgroundEnabled = false; Widget? postfixWidget; Widget? preFixWidget; + bool numbersOnly; TxtField({ Key? key, @@ -61,6 +63,7 @@ class TxtField extends StatelessWidget { this.postfixWidget, this.preFixWidget, this.onPostFixPressed, + this.numbersOnly = false, }) : super(key: key); @override @@ -97,6 +100,7 @@ class TxtField extends StatelessWidget { obscureText: isPasswordEnabled ?? false, onChanged: onChanged, onSubmitted: onSubmitted, + inputFormatters: numbersOnly ? [FilteringTextInputFormatter.allow(RegExp('[0-9]'))] : [], decoration: InputDecoration( labelText: lable, alignLabelWithHint: true, diff --git a/pubspec.yaml b/pubspec.yaml index 4e176a9..4a5f47b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,16 +41,24 @@ dependencies: signalr_core: ^1.1.1 logging: ^1.2.0 percent_indicator: ^4.2.3 + change_app_package_name: ^1.3.0 + + + # Firebase Packages + + firebase_messaging: ^15.0.4 + firebase_core: ^3.3.0 + flutter_local_notifications: ^17.2.1+2 # google google_maps_flutter: ^2.1.1 geolocator: any -# geocoding: ^2.1.0 + # geocoding: ^2.1.0 geocoding: ^3.0.0 -# Auth + # Auth local_auth: ^2.2.0 huawei_fido: ^6.3.0+305