16 April, 2025

faiz_development_common
Faiz Hashmi 7 months ago
parent 6bea3daf78
commit da9c03a30f

@ -811,6 +811,8 @@
"selfPickup": "الالتقاط الذاتي",
"updateYourLocationInfo": "قم بتحديث معلومات موقعك",
"initiateSelfPickup": "بدء الاستلام الذاتي",
"selfPickupStatus": "حالة الالتقاط الذاتي"
"selfPickupStatus": "حالة الالتقاط الذاتي",
"myDraftAds": "مسودتي للإعلانات",
"scheduleDeletedSuccessfully": "تم حذف الجدول بنجاح",
"addValidAddress": "رجى إضافة عنوان صالح"
}

@ -809,5 +809,8 @@
"selfPickup": "Self Pickup",
"updateYourLocationInfo": "Update your location information",
"initiateSelfPickup": "Initiate Self Pickup",
"selfPickupStatus": "Self Pickup Status"
"selfPickupStatus": "Self Pickup Status",
"myDraftAds": "My Draft Ads",
"scheduleDeletedSuccessfully": "The schedule has been deleted successfully",
"addValidAddress": "Please add a valid address"
}

@ -9,6 +9,7 @@ import 'package:mc_common_app/views/advertisement/ads_buyer_chats_view.dart';
import 'package:mc_common_app/views/advertisement/ads_detail_view/ads_detail_view.dart';
import 'package:mc_common_app/views/advertisement/ads_filter_view.dart';
import 'package:mc_common_app/views/advertisement/create_ad_view.dart';
import 'package:mc_common_app/views/advertisement/my_draft_ads_view.dart';
import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart';
import 'package:mc_common_app/views/chat/chat_view.dart';
import 'package:mc_common_app/views/payments/payment_methods_view.dart';
@ -130,6 +131,7 @@ class AppRoutes {
static const String createAdView = "/createAdView";
static const String adsFilterView = "/adsFilterView";
static const String adsBuyerChatsListView = "/adsBuyersChatListView";
static const String myDraftAdsView = "/myDraftAdsView";
// Payments
static const String paymentMethodsView = "/paymentMethodsView";
@ -208,6 +210,7 @@ class AppRoutes {
AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
AppRoutes.createAdView: (context) => const CreateAdView(),
AppRoutes.adsFilterView: (context) => const AdsFilterView(),
AppRoutes.myDraftAdsView: (context) => const MyDraftAdsView(),
AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(arguments: ModalRoute.of(context)!.settings.arguments as List<dynamic>),
AppRoutes.chatView: (context) => ChatView(chatViewArguments: ModalRoute.of(context)!.settings.arguments as ChatViewArguments),
AppRoutes.adsBuyerChatsListView: (context) => AdsBuyerChatsView(buyersListViewArguments: ModalRoute.of(context)!.settings.arguments as List<BuyersChatForAdsModel>),

@ -1012,7 +1012,7 @@ extension SelfPickupStatusEnumExt on int {
if (this == -1) {
return SelfPickupRequestStatusEnum.allRequests;
} else if (this == 0) {
return SelfPickupRequestStatusEnum.allRequests;
return SelfPickupRequestStatusEnum.pending;
} else if (this == 1) {
return SelfPickupRequestStatusEnum.preparingToCollect;
} else if (this == 2) {
@ -1028,6 +1028,8 @@ extension SelfPickupStatusEnumToInt on SelfPickupRequestStatusEnum {
int getIdFromSelfPickupStatusEnum() {
switch (this) {
case SelfPickupRequestStatusEnum.allRequests:
return -1;
case SelfPickupRequestStatusEnum.pending:
return 0;
case SelfPickupRequestStatusEnum.preparingToCollect:
return 1;

@ -827,7 +827,10 @@ class CodegenLoader extends AssetLoader{
"selfPickup": "الالتقاط الذاتي",
"updateYourLocationInfo": "قم بتحديث معلومات موقعك",
"initiateSelfPickup": "بدء الاستلام الذاتي",
"selfPickupStatus": "حالة الالتقاط الذاتي"
"selfPickupStatus": "حالة الالتقاط الذاتي",
"myDraftAds": "مسودتي للإعلانات",
"scheduleDeletedSuccessfully": "تم حذف الجدول بنجاح",
"addValidAddress": "رجى إضافة عنوان صالح"
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1640,7 +1643,10 @@ static const Map<String,dynamic> en_US = {
"selfPickup": "Self Pickup",
"updateYourLocationInfo": "Update your location information",
"initiateSelfPickup": "Initiate Self Pickup",
"selfPickupStatus": "Self Pickup Status"
"selfPickupStatus": "Self Pickup Status",
"myDraftAds": "My Draft Ads",
"scheduleDeletedSuccessfully": "The schedule has been deleted successfully",
"addValidAddress": "Please add a valid address"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -791,5 +791,8 @@ abstract class LocaleKeys {
static const updateYourLocationInfo = 'updateYourLocationInfo';
static const initiateSelfPickup = 'initiateSelfPickup';
static const selfPickupStatus = 'selfPickupStatus';
static const myDraftAds = 'myDraftAds';
static const scheduleDeletedSuccessfully = 'scheduleDeletedSuccessfully';
static const addValidAddress = 'addValidAddress';
}

@ -2,7 +2,6 @@ import 'package:logger/logger.dart';
Logger logger = Logger(printer: PrettyPrinter(printEmojis: false, colors: true, printTime: false));
bool disableThingsForQA = true;
// Language Tile in Settings
@ -12,4 +11,3 @@ bool disableThingsForQA = true;
// 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

@ -137,7 +137,7 @@ class AdDetailsModel {
taxPrice = json['taxPrice'];
totalPrice = json['totalPrice'];
userID = json['userID'];
vehiclePostingID = json['vehiclePostingID'];
vehiclePostingID = (json['vehiclePostingID'] == null || json['vehiclePostingID'] == 0) ? json['id'] : 0;
qrCodePath = json['qrCodePath'];
isCustomerAcknowledged = json['isCustomerAcknowledged'];
createdByRole = json['createdByRole'];
@ -156,7 +156,7 @@ class AdDetailsModel {
adOwnerName = json['vehicle'] != null ? (json['vehicle']['adOwnerName'] ?? "") : "";
adOwnerEmail = json['vehicle'] != null ? (json['vehicle']['adOwnerEmail'] ?? "") : "";
adOwnerDetails = (json['vehicle'] != null && json['vehicle']['aDsUser'] != null) ? (AdOwnerDetails.fromJson(json['vehicle']['aDsUser'])) : null;
adPostStatus = (json['statusID'] as int).toAdPostEnum();
adPostStatus = ((json['statusID'] ?? 1) as int).toAdPostEnum();
adReserveStatus = AdReserveStatus.defaultStatus;
createdByRoleEnum = (json['createdByRole'] as int).toCreatedByRoleEnum();
isMyAd = isMyAds;

@ -140,7 +140,7 @@ class AdsRepoImp implements AdsRepo {
"imageName": element.imageName,
"imageUrl": element.imageUrl,
"imageStr": element.imageStr,
"vehiclePostingID": element.vehiclePostingID ?? 0,
"vehiclePostingID": isCreateNew ? 0 : element.vehiclePostingID ?? 0,
"vehiclePosting": null,
};
vehiclePostingImages.add(imageMap);
@ -157,14 +157,14 @@ class AdsRepoImp implements AdsRepo {
"comment": element.comment,
"vehicleImageBase64": element.vehicleImageBase64,
"vehicleDamagePartID": element.vehicleDamagePartID,
"vehiclePostingID": element.vehiclePostingID ?? 0,
"vehiclePostingID": isCreateNew ? 0 : element.vehiclePostingID ?? 0,
"isActive": true
};
vehiclePostingDamageParts.add(imageMap);
});
var postParams = {
"ads": {
"id": adsCreationPayloadModel.ads!.id ?? 0,
"id": isCreateNew ? 0 : adsCreationPayloadModel.ads!.id ?? 0,
"adsDurationID": adsCreationPayloadModel.ads!.adsDurationID,
"startDate": adsCreationPayloadModel.ads!.startDate,
"countryId": adsCreationPayloadModel.ads!.countryId,
@ -174,7 +174,7 @@ class AdsRepoImp implements AdsRepo {
"isOnWhatsApp": adsCreationPayloadModel.ads!.isOnWhatsApp ?? false,
},
"vehiclePosting": {
"id": adsCreationPayloadModel.vehiclePosting!.id ?? 0,
"id": isCreateNew ? 0 : adsCreationPayloadModel.vehiclePosting!.id ?? 0,
"userID": adsCreationPayloadModel.vehiclePosting!.userID,
"vehicleType": adsCreationPayloadModel.vehiclePosting!.vehicleType,
"vehicleModelID": adsCreationPayloadModel.vehiclePosting!.vehicleModelID,
@ -224,21 +224,23 @@ class AdsRepoImp implements AdsRepo {
List vehiclePostingImages = [];
List vehiclePostingDamageParts = [];
if (stepNo == AdCreationStepsEnum.vehicleDetails) {
adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) {
var imageMap = {
"id": element.id ?? 0,
"imageName": element.imageName,
"imageUrl": element.imageUrl,
"imageStr": element.imageStr,
"vehiclePostingDraftID": element.vehiclePostingID ?? 0,
"vehiclePosting": null,
};
vehiclePostingImages.add(imageMap);
});
if (adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages != null) {
adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach(
(element) {
var imageMap = {
"id": element.id ?? 0,
"imageName": element.imageName,
"imageUrl": element.imageUrl,
"imageStr": element.imageStr,
"vehiclePostingDraftID": element.vehiclePostingID ?? 0,
"vehiclePosting": null,
};
vehiclePostingImages.add(imageMap);
},
);
}
if (stepNo == AdCreationStepsEnum.damageParts) {
if (adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts != null) {
adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) {
var imageMap = {
"id": element.id ?? 0,

@ -240,6 +240,7 @@ enum ShippingRequestStatusEnum {
enum SelfPickupRequestStatusEnum {
allRequests,
pending,
preparingToCollect,
readyToCollect,
collected,

@ -339,6 +339,9 @@ class Utils {
case SelfPickupRequestStatusEnum.allRequests:
return "All Requests";
case SelfPickupRequestStatusEnum.pending:
return "Pending";
case SelfPickupRequestStatusEnum.preparingToCollect:
return "Preparing To Collect";
@ -377,6 +380,9 @@ class Utils {
case SelfPickupRequestStatusEnum.allRequests:
return MyColors.submittedColor;
case SelfPickupRequestStatusEnum.pending:
return MyColors.pendingColor;
case SelfPickupRequestStatusEnum.preparingToCollect:
return MyColors.submittedColor;
@ -767,12 +773,12 @@ class NoInternetDialog {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
LocaleKeys.connectionProblem,
title: Text(
LocaleKeys.connectionProblem.tr(),
textAlign: TextAlign.center,
),
content: const Text(
LocaleKeys.pleaseCheckConnection,
content: Text(
LocaleKeys.pleaseCheckConnection.tr(),
textAlign: TextAlign.center,
),
actions: [

@ -82,6 +82,7 @@ class AdVM extends BaseVM {
// Edit Variables Amir
bool isExtendAdEditEnabled = false;
bool isAdEditEnabled = false;
bool isDraftEditEnabled = false;
AdDetailsModel? previousAdDetails;
List<AdDetailsModel> myDraftAds = [];
@ -347,15 +348,20 @@ class AdVM extends BaseVM {
int pageIndexForMyDrafts = 1;
Future<void> getMyDraftAds() async {
pageIndexForMyAds = 1;
hasMoreDataForMyAds = true;
setState(ViewState.busy);
myDraftAds = await adsRepo.getMyDraftAds();
notifyListeners();
setState(ViewState.idle);
try {
pageIndexForMyAds = 1;
hasMoreDataForMyAds = true;
setState(ViewState.busy);
myDraftAds = await adsRepo.getMyDraftAds();
notifyListeners();
setState(ViewState.idle);
} catch (e) {
setState(ViewState.idle);
logger.e(e.toString());
}
}
Future<void> fetchMoreDraftAds({required AdPostStatus adsStatus}) async {
Future<void> fetchMoreDraftAds() async {
if (isLoadingMore) return;
hasMoreDataForMyDraftsAds = true;
isLoadingMore = true;
@ -1214,6 +1220,8 @@ class AdVM extends BaseVM {
void onBackButtonPressed(BuildContext context) {
switch (currentProgressStep) {
case AdCreationStepsEnum.vehicleDetails:
isAdEditEnabled = false;
isDraftEditEnabled = false;
resetValues();
pop(context);
break;
@ -1235,12 +1243,25 @@ class AdVM extends BaseVM {
Future<int> saveAdVehicleDetailsDraft({required bool isNew, required BuildContext context, required AdCreationStepsEnum stepNoEnum}) async {
AppState appState = injector.get<AppState>();
log("selectionDurationStartDate: $selectionDurationStartDate");
log("specialServiceCards: ${specialServiceCards.length}");
List<int> adsSelectedServices = [];
for (var value in specialServiceCards) {
adsSelectedServices.add(value.serviceSelectedId!.selectedId);
}
Utils.showLoading(context);
try {
Ads ads = Ads(
id: !isNew ? previousAdDetails!.id : 0,
adsDurationID: vehicleAdDurationId.selectedId == -1 ? 0 : vehicleAdDurationId.selectedId,
startDate: selectionDurationStartDate,
countryId: vehicleCountryId.selectedId,
specialServiceIDs: adsSelectedServices,
showContactDetail: isPhoneNumberShown,
isOnWhatsApp: isNumberOnWhatsApp,
);
List<VehiclePostingImages> vehicleImages = [];
@ -1248,6 +1269,22 @@ class AdVM extends BaseVM {
vehicleImages.add(await convertFileToVehiclePostingImages(imageModel: image));
}
List<VehiclePostingDamageParts> vehicleDamageImages = [];
for (var card in vehicleDamageCards) {
if (card.partImages != null && card.partImages!.isNotEmpty) {
for (var image in card.partImages!) {
VehiclePostingDamageParts stringImage = await convertFileToVehiclePostingDamageParts(
imageModel: image,
damagePartId: card.partSelectedId!.selectedId,
commentParam: card.damagePartDescription ?? "",
);
vehicleDamageImages.add(stringImage);
}
}
}
VehiclePosting vehiclePosting = VehiclePosting(
id: !isNew ? previousAdDetails!.vehiclePostingID : null,
userID: appState.getUser.data!.userInfo!.userId,
@ -1270,6 +1307,9 @@ class AdVM extends BaseVM {
warantyYears: int.parse(warrantyDuration),
demandAmount: int.parse(vehicleDemandAmount),
vehiclePostingImages: vehicleImages,
vehiclePostingDamageParts: vehicleDamageImages,
phoneNo: isPhoneNumberShown ? adPhoneNumberDialCode + adPhoneNumber : null,
whatsAppNo: (isPhoneNumberShown && isNumberOnWhatsApp) ? adPhoneNumberDialCode + adPhoneNumber : null,
);
AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting);
@ -1336,6 +1376,7 @@ class AdVM extends BaseVM {
return;
}
isAdEditEnabled = false;
isDraftEditEnabled = false;
isExtendAdEditEnabled = false;
Utils.hideLoading(context);
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
@ -1693,7 +1734,11 @@ class AdVM extends BaseVM {
log("selectionDurationStartDate: $selectionDurationStartDate");
Ads ads = Ads(
id: isAdEditEnabled ? previousAdDetails!.id : null,
id: isDraftEditEnabled
? null
: isAdEditEnabled
? previousAdDetails!.id
: null,
adsDurationID: vehicleAdDurationId.selectedId == -1 ? 0 : vehicleAdDurationId.selectedId,
startDate: selectionDurationStartDate,
countryId: vehicleCountryId.selectedId,
@ -1751,7 +1796,11 @@ class AdVM extends BaseVM {
AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting);
GenericRespModel respModel = await adsRepo.createOrUpdateAd(adsCreationPayloadModel: adsCreationPayloadModel, isCreateNew: !isAdEditEnabled, isExtendAdEditEnabled: isExtendAdEditEnabled);
GenericRespModel respModel = await adsRepo.createOrUpdateAd(
adsCreationPayloadModel: adsCreationPayloadModel,
isCreateNew: isDraftEditEnabled ? true : !isAdEditEnabled,
isExtendAdEditEnabled: isExtendAdEditEnabled,
);
Utils.showToast(respModel.message.toString());
@ -2289,13 +2338,16 @@ class AdVM extends BaseVM {
return [];
}
void onEditUpdateAdPressed({required BuildContext context, required AdDetailsModel previousDetails, required bool isFromExtendAd}) {
void onEditUpdateAdPressed({required BuildContext context, required AdDetailsModel previousDetails, required bool isFromExtendAd, bool isForDraft = false}) {
isAdEditEnabled = true;
isDraftEditEnabled = true;
isExtendAdEditEnabled = isFromExtendAd;
previousAdDetails = previousDetails;
autoFillSelectedVehicleType();
autoFillSelectedVehicleAdsDuration();
if (isForDraft) {
autoFillSelectedVehicleAdsDetails();
}
navigateWithName(context, AppRoutes.selectAdTypeView, arguments: [AppState().currentAppType == AppType.provider, isFromExtendAd, previousDetails.id]);
}
@ -2324,12 +2376,14 @@ class AdVM extends BaseVM {
void autoFillSelectedVehicleType() async {
if (vehicleTypes.isEmpty) {
await getVehicleTypes();
return;
// return;
}
if (vehicleTypes.isNotEmpty) {
for (var vehicle in vehicleTypes) {
vehicle.isSelected = false;
if (vehicle.id == previousAdDetails!.vehicle?.vehicleType) {
vehicle.isSelected = true;
log("Hi: ${vehicle.vehicleTypeName}");
break;
}
}
@ -2370,6 +2424,9 @@ class AdVM extends BaseVM {
}
void autoFillSelectedVehicleAdsDetails() async {
if (vehicleBrands.isEmpty) {
await getVehicleBrandsByVehicleTypeId();
}
int index = vehicleBrands.indexWhere((element) => element.id == previousAdDetails!.vehicle!.model!.vehicleBrandID);
if (index != -1) {
@ -2403,6 +2460,7 @@ class AdVM extends BaseVM {
for (var element in previousAdDetails!.vehicle!.image!) {
if (element.imageUrl != null) {
ImageModel imageModel = ImageModel(id: element.id, filePath: element.imageUrl, isFromNetwork: true);
log("running");
pickedPostingImages.add(imageModel);
}
}
@ -2444,12 +2502,16 @@ class AdVM extends BaseVM {
address: "",
serviceTime: "",
);
addNewSpecialServiceCard(specialServiceCard: specialServiceCard);
int index = ifSpecialServiceAlreadyThere(element.specialServiceID!);
log("Found at : $index");
if (index == -1) {
addNewSpecialServiceCard(specialServiceCard: specialServiceCard);
}
}
}
// selectionDurationStartDate = DateHelper.formatDateT(previousAdDetails!.startdate ?? "");
selectionDurationStartDate = "";
selectionDurationStartDate = ""; // You have to mention this each time
isPhoneNumberShown = previousAdDetails!.showContactDetail ?? false;
adPhoneNumber = previousAdDetails!.adOwnerDetails!.mobileNo ?? "";

@ -307,9 +307,7 @@ class AppointmentsVM extends BaseVM {
}
void removeServiceInCurrentAppointment(int index) {
int serviceId = servicesInCurrentAppointment
.elementAt(index)
.serviceProviderServiceId ?? -1;
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
servicesInCurrentAppointment[index].serviceItems!.clear();
servicesInCurrentAppointment.removeAt(index);
@ -372,13 +370,15 @@ class AppointmentsVM extends BaseVM {
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForProvider
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
log("myUpComingAppointments: ${myUpComingAppointments.length}");
}
if (isNeedCustomerFilter) {
log("myFilteredAppointmentsForProvider: ${myFilteredAppointmentsForProvider.length}");
myFilteredAppointmentsForProvider = findAppointmentsBasedOnCustomers(myFilteredAppointmentsForProvider);
}
notifyListeners();
@ -400,8 +400,8 @@ class AppointmentsVM extends BaseVM {
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForCustomers
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
}
@ -416,19 +416,14 @@ class AppointmentsVM extends BaseVM {
List<AppointmentListModel> groupedList = uniqueCustomerIDs.map((id) {
List<AppointmentListModel> list = appointments.where((item) => item.customerID == id).toList();
list.sort((a, b) =>
DateHelper
.parseStringToDate(DateHelper.formatDateT(b.appointmentDate!))
.millisecondsSinceEpoch
.compareTo(DateHelper
.parseStringToDate(DateHelper.formatDateT(a.appointmentDate!))
.millisecondsSinceEpoch));
list.sort((a, b) => DateHelper.parseStringToDate(DateHelper.formatDateT(b.appointmentDate!))
.millisecondsSinceEpoch
.compareTo(DateHelper.parseStringToDate(DateHelper.formatDateT(a.appointmentDate!)).millisecondsSinceEpoch));
AppointmentListModel model = list.first;
model.customerAppointmentList = list;
return model;
}).toList();
return groupedList;
}
@ -492,6 +487,9 @@ class AppointmentsVM extends BaseVM {
}
bool isShowMergeButton() {
if (myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList == null) {
return false;
}
return myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList!.every((appointment) => appointment.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList!.length > 1;
}
@ -507,7 +505,7 @@ class AppointmentsVM extends BaseVM {
void updateCheckBoxInMergeRequest(int currentIndex) {
myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected =
!(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
!(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
int count = countSelected(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList ?? []);
if (count > 1) {
@ -519,10 +517,7 @@ class AppointmentsVM extends BaseVM {
}
int countSelected(List<AppointmentListModel> appointments) {
return appointments
.where((appointment) => appointment.isSelected == true)
.toList()
.length;
return appointments.where((appointment) => appointment.isSelected == true).toList().length;
}
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
@ -698,14 +693,13 @@ class AppointmentsVM extends BaseVM {
Column(
children: List.generate(
selectedService.serviceItems!.length,
(index) =>
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} ${LocaleKeys.sar.tr()}".toText(fontSize: 12, isBold: true),
],
),
(index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} ${LocaleKeys.sar.tr()}".toText(fontSize: 12, isBold: true),
],
),
),
),
Row(
@ -924,10 +918,7 @@ class AppointmentsVM extends BaseVM {
return InfoBottomSheet(
title: LocaleKeys.reportComplaint.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery
.of(context)
.viewInsets
.bottom),
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

@ -94,7 +94,11 @@ class DashboardVMProvider extends BaseVM {
}
await shippingManagementVM.populateShippingRequestFilterList();
await shippingManagementVM.populateSelfPickupRequestFilterList();
await appointmentVM.applyFilterOnAppointmentsVMForProviders(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, shouldPopulateUpcoming: true);
await appointmentVM.applyFilterOnAppointmentsVMForProviders(
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true,
shouldPopulateUpcoming: true,
);
await adVM.getVehicleTypes();
await adVM.getVehicleAdsDuration();

@ -861,7 +861,7 @@ class RequestsVM extends BaseVM {
Utils.showToast(LocaleKeys.addValidDescription.tr());
isValid = false;
} else if (address.isEmpty && requestTypeId.selectedId == 2) {
Utils.showToast(LocaleKeys.addValidDescription.tr());
Utils.showToast(LocaleKeys.addValidAddress.tr());
isValid = false;
}
return isValid;

@ -66,6 +66,9 @@ class ShippingManagementVM extends BaseVM {
selfPickupRequestsStatusesList.add(FilterListModel(title: selfPickupStatusEnums[i].enumValueStrDes, isSelected: false, id: selfPickupStatusEnums[i].enumValue));
}
selfPickupRequestsFilterOptions.sort((FilterListModel a, FilterListModel b) => a.id.compareTo(b.id));
selfPickupRequestsStatusesList.sort((FilterListModel a, FilterListModel b) => a.id.compareTo(b.id));
selfPickupRequestsFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum.allRequests), isSelected: true, id: -1));
notifyListeners();
}
@ -82,6 +85,9 @@ class ShippingManagementVM extends BaseVM {
}
int index = shippingRequestFilterOptions.indexWhere((element) => element.id == 0);
shippingRequestFilterOptions.sort((FilterListModel a, FilterListModel b) => a.id.compareTo(b.id));
shippingRequestStatusesList.sort((FilterListModel a, FilterListModel b) => a.id.compareTo(b.id));
if (index == -1) {
log("index: $index");
shippingRequestFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(0.toShippingStatusEnum()), isSelected: false, id: 0));

@ -23,6 +23,7 @@ class AdsListWidget extends StatelessWidget {
final bool isAdsFragment;
final bool shouldShowAdStatus;
final bool hasMoreData;
final bool isDraftAds;
final Function()? onFetchMoreAds;
const AdsListWidget({
@ -30,6 +31,7 @@ class AdsListWidget extends StatelessWidget {
required this.adsList,
required this.shouldShowAdStatus,
required this.hasMoreData,
required this.isDraftAds,
this.onFetchMoreAds,
this.scrollPhysics,
this.isAdsFragment = false,
@ -47,7 +49,6 @@ class AdsListWidget extends StatelessWidget {
}
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
log("hasMoreData: $hasMoreData");
if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent && hasMoreData) {
if (onFetchMoreAds != null) {
onFetchMoreAds!();
@ -64,9 +65,20 @@ class AdsListWidget extends StatelessWidget {
adDetails: adsList[index],
isAdsFragment: isAdsFragment,
shouldShowAdStatus: shouldShowAdStatus,
).onPress(() => navigateWithName(context, AppRoutes.adsDetailView, arguments: adsList[index])).toViewOnly(context, onTap: () {
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
});
).onPress(
() {
if (isDraftAds) {
context.read<AdVM>().onEditUpdateAdPressed(
context: context,
previousDetails: adsList[index],
isFromExtendAd: false,
isForDraft: true,
);
} else {
navigateWithName(context, AppRoutes.adsDetailView, arguments: adsList[index]);
}
},
).toViewOnly(context, onTap: () => navigateWithName(context, AppRoutes.loginWithPassword, arguments: false));
},
separatorBuilder: (BuildContext context, int index) {
return 12.height;
@ -89,110 +101,120 @@ class AdCard extends StatelessWidget {
return Stack(
alignment: Alignment.center,
children: [
Row(
children: [
adDetails.vehicle!.image!.first.imageUrl.buildNetworkImage(
width: 80,
height: 80,
fit: BoxFit.cover,
if (adDetails.vehicle == null) ...[
Expanded(
child: Column(
children: [
"Zahoor will update the Ad Format".toText(),
],
),
12.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (isAdsFragment && adDetails.adPostStatus! == AdPostStatus.sold) ...[
Utils.statusContainerChip(text: adDetails.statuslabel!, chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)),
] else if (isAdsFragment && !context.read<AdVM>().isExploreAdsTapped) ...[
Utils.statusContainerChip(text: adDetails.statuslabel!, chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)),
],
(adDetails.vehicle!.vehicleTitle ?? "").toText(
fontSize: 16,
letterSpacing: -0.64,
height: 25 / 16,
),
Row(
children: [
("${LocaleKeys.model.tr()}:").toText(
fontSize: 12,
color: MyColors.lightTextColor,
letterSpacing: -0.48,
height: 18 / 12,
),
2.width,
(adDetails.vehicle!.modelyear!.label ?? "").toText(
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
],
),
Row(
children: [
("${LocaleKeys.mileage.tr()}:").toText(
color: MyColors.lightTextColor,
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
2.width,
(adDetails.vehicle!.mileage!.mileageEnd ?? "").toText(
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
),
] else ...[
Row(
children: [
adDetails.vehicle!.image!.first.imageUrl.buildNetworkImage(
width: 80,
height: 80,
fit: BoxFit.cover,
),
12.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (isAdsFragment && adDetails.adPostStatus! == AdPostStatus.sold && adDetails.statuslabel != null && adDetails.statuslabel!.isNotEmpty) ...[
Utils.statusContainerChip(text: adDetails.statuslabel ?? "", chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)),
] else if (isAdsFragment && !context.read<AdVM>().isExploreAdsTapped && adDetails.statuslabel != null && adDetails.statuslabel!.isNotEmpty) ...[
Utils.statusContainerChip(text: adDetails.statuslabel ?? "", chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)),
],
),
],
(adDetails.vehicle!.vehicleTitle ?? "").toText(
fontSize: 16,
letterSpacing: -0.64,
height: 25 / 16,
),
Row(
children: [
("${LocaleKeys.model.tr()}:").toText(
fontSize: 12,
color: MyColors.lightTextColor,
letterSpacing: -0.48,
height: 18 / 12,
),
2.width,
(adDetails.vehicle!.modelyear!.label ?? "").toText(
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
],
),
Row(
children: [
("${LocaleKeys.mileage.tr()}:").toText(
color: MyColors.lightTextColor,
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
2.width,
(adDetails.vehicle!.mileage!.mileageEnd ?? "").toText(
fontSize: 12,
letterSpacing: -0.48,
height: 18 / 12,
),
],
),
],
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(adDetails.vehicle!.cityName ?? "").toText(color: MyColors.lightTextColor),
adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(color: MyColors.lightTextColor) : const SizedBox(),
],
),
],
),
8.height,
Row(
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 19, isBold: true, letterSpacing: -1.16, height: 29 / 19),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10).paddingOnly(bottom: 3),
(adDetails.vehicle!.cityName ?? "").toText(color: MyColors.lightTextColor),
adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(color: MyColors.lightTextColor) : const SizedBox(),
],
),
),
SvgPicture.asset(
MyAssets.arrowRight,
height: 9.69,
width: 13,
),
],
),
8.height,
Row(
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 19, isBold: true, letterSpacing: -1.16, height: 29 / 19),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10).paddingOnly(bottom: 3),
],
),
),
SvgPicture.asset(
MyAssets.arrowRight,
height: 9.69,
width: 13,
),
// const Icon(Icons.arrow_forward)
],
),
],
// const Icon(Icons.arrow_forward)
],
),
],
),
),
),
],
),
],
),
],
if (false)
Container(
height: 100,

@ -1,9 +1,13 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_duration_container.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_review_containers.dart';
@ -94,8 +98,14 @@ class BuildFooterButton extends StatelessWidget {
maxHeight: 55,
title: LocaleKeys.cancel.tr(),
onPressed: () {
adVm.isDraftEditEnabled = false;
adVm.resetValues();
pop(context);
if (AppState().currentAppType == AppType.customer) {
pop(context);
}
Utils.showToast('Saved as Draft');
adVm.getMyDraftAds();
},
backgroundColor: MyColors.greyButtonColor,
),
@ -122,8 +132,15 @@ class BuildFooterButton extends StatelessWidget {
maxHeight: 55,
title: LocaleKeys.cancel.tr(),
onPressed: () {
adVm.isDraftEditEnabled = false;
adVm.resetValues();
pop(context);
if (AppState().currentAppType == AppType.customer) {
pop(context);
}
Utils.showToast('Saved as Draft');
adVm.getMyDraftAds();
},
backgroundColor: MyColors.greyButtonColor,
),
@ -150,8 +167,15 @@ class BuildFooterButton extends StatelessWidget {
maxHeight: 55,
title: LocaleKeys.cancel.tr(),
onPressed: () {
adVm.isDraftEditEnabled = false;
adVm.resetValues();
pop(context);
if (AppState().currentAppType == AppType.customer) {
pop(context);
}
Utils.showToast('Saved as Draft');
adVm.getMyDraftAds();
},
backgroundColor: MyColors.greyButtonColor,
),

@ -0,0 +1,68 @@
import 'dart:async';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/advertisement/components/ads_list_widget.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class MyDraftAdsView extends StatefulWidget {
const MyDraftAdsView({super.key});
@override
State<MyDraftAdsView> createState() => _MyDraftAdsViewState();
}
class _MyDraftAdsViewState extends State<MyDraftAdsView> {
@override
void initState() {
scheduleMicrotask(() async => context.read<AdVM>().getMyDraftAds());
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.myDraftAds.tr()),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
children: [
Expanded(
child: RefreshIndicator(
onRefresh: () async {
await adVM.getMyDraftAds();
},
child: adVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: AdsListWidget(
isAdsFragment: true,
isDraftAds: true,
shouldShowAdStatus: false,
adsList: adVM.myDraftAds,
hasMoreData: adVM.hasMoreDataForMyDraftsAds,
onFetchMoreAds: () async {
await adVM.fetchMoreDraftAds();
},
),
),
),
if (adVM.isLoadingMore) ...[
const Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
))
]
],
),
),
);
});
}
}

@ -78,7 +78,8 @@ class SelectAdTypeView extends StatelessWidget {
onTap: () async {
adVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: vehicleTypeModel.id!, selectedOption: vehicleTypeModel.vehicleTypeName ?? "", errorValue: ""));
if (adVM.isAdEditEnabled) {
adVM.autoFillSelectedVehicleAdsDetails();
adVM.
autoFillSelectedVehicleAdsDetails();
}
if (AppState().currentAppType == AppType.provider) {
if (isFromExtendAd && !adVM.isAdEditEnabled) {

@ -150,6 +150,7 @@ class AdsFragment extends StatelessWidget {
? const Center(child: CircularProgressIndicator())
: AdsListWidget(
isAdsFragment: true,
isDraftAds: false,
shouldShowAdStatus: !adVM.isExploreAdsTapped,
adsList: getAdsList(adVM),
hasMoreData: adVM.isExploreAdsTapped ? adVM.hasMoreDataForExploreAds : adVM.hasMoreDataForMyAds,

@ -234,7 +234,7 @@ class CreateRequestPage extends StatelessWidget {
onChanged: (e) => requestsVM.updateAddress(e),
),
8.height,
] ,
],
if (requestsVM.pickedVehicleImages.isEmpty) ...[
DottedRectContainer(
onTap: () => context.read<RequestsVM>().pickMultipleImages(),
@ -285,5 +285,3 @@ class CreateRequestPage extends StatelessWidget {
);
}
}

@ -112,6 +112,19 @@ class _SettingOptionsMoreState extends State<SettingOptionsMore> {
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
}),
],
CustomSettingOptionsTile(
leadingWidget: SvgPicture.asset(
MyAssets.icAds,
height: 20,
width: 20,
color: MyColors.darkIconColor,
),
titleText: LocaleKeys.myDraftAds.tr(),
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.myDraftAdsView);
},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),

Loading…
Cancel
Save