Ad Module with UI changes!

merge-requests/10/head
FaizHashmiCS22 3 years ago
parent 9bf716eb39
commit 439fae0ec5

@ -84,6 +84,7 @@ class GlobalConsts {
static String warrantyError = "Warranty Duration Cannot be Empty";
static String vehicleDescError = "Vehicle Description Cannot be Empty";
static String attachImageError = "You must add at least 3 images";
static String attachDamagePartImage = "Please add part image";
static String adDurationDateError = "Ad Duration start date cannot be empty";
}

@ -11,20 +11,24 @@ class SpecialServiceModel {
List<Details>? details;
List<Office>? office;
bool? isDelivery;
bool? isSelected;
bool? isChecked;
SpecialServiceModel(
{this.id,
this.name,
this.description,
this.price,
this.specialServiceType,
this.specialServiceTypeName,
this.isActive,
this.startDate,
this.endDate,
this.details,
this.office,
this.isDelivery});
this.name,
this.description,
this.price,
this.specialServiceType,
this.specialServiceTypeName,
this.isActive,
this.startDate,
this.endDate,
this.details,
this.office,
this.isSelected = false,
this.isChecked = false,
this.isDelivery});
SpecialServiceModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -49,6 +53,8 @@ class SpecialServiceModel {
});
}
isDelivery = json['isDelivery'];
isSelected = false;
isChecked = false;
}
Map<String, dynamic> toJson() {
@ -80,8 +86,7 @@ class Details {
int? tocity;
int? price;
Details(
{this.id, this.specialServiceID, this.fromcity, this.tocity, this.price});
Details({this.id, this.specialServiceID, this.fromcity, this.tocity, this.price});
Details.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -110,13 +115,7 @@ class Office {
String? city;
int? specialServiceID;
Office(
{this.id,
this.officeAreaName,
this.officeAreaNameN,
this.cityID,
this.city,
this.specialServiceID});
Office({this.id, this.officeAreaName, this.officeAreaNameN, this.cityID, this.city, this.specialServiceID});
Office.fromJson(Map<String, dynamic> json) {
id = json['id'];

@ -406,8 +406,10 @@ class VehiclePartModel {
String? partName;
String? description;
bool? isActive;
bool? isSelected;
bool? isChecked;
VehiclePartModel({this.id, this.partNo, this.partName, this.description, this.isActive});
VehiclePartModel({this.id, this.partNo, this.partName, this.description, this.isActive, this.isSelected});
VehiclePartModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -415,6 +417,8 @@ class VehiclePartModel {
partName = json['partName'];
description = json['description'];
isActive = json['isActive'];
isSelected = false;
isChecked = false;
}
Map<String, dynamic> toJson() {

@ -0,0 +1,6 @@
class FilterListModel {
String title;
bool isSelected;
FilterListModel({required this.isSelected, required this.title});
}

@ -1,4 +1,5 @@
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/models/advertisment_models/ad_details_model.dart';
@ -9,7 +10,6 @@ import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.
import 'package:mc_common_app/models/user/cities.dart';
import 'package:mc_common_app/models/user/country.dart';
import 'package:mc_common_app/models/user/role.dart';
import 'package:mc_common_app/classes/app_state.dart';
abstract class CommonRepo {
Future<Country> getAllCountries();
@ -50,7 +50,7 @@ abstract class CommonRepo {
Future<AdsGenericModel> createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel});
Future<List<AdDetailsModel>> getAllAds();
Future<List<AdDetailsModel>> getAllAds({required bool isMyAds});
Future<List<AdDetailsModel>> getMyAds();
}
@ -332,11 +332,16 @@ class CommonRepoImp implements CommonRepo {
}
@override
Future<List<AdDetailsModel>> getAllAds() async {
Future<List<AdDetailsModel>> getAllAds({required isMyAds}) async {
var params = {
"userID": appState.getUser.data!.userInfo!.userId ?? "",
};
AdsGenericModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => AdsGenericModel.fromJson(json),
ApiConsts.vehicleAdsGet,
queryParameters: isMyAds ? params : null,
);
List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index]));
return vehicleAdsDetails;

@ -1,5 +1,6 @@
import 'dart:convert';
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';
@ -10,6 +11,7 @@ import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart
import 'package:mc_common_app/models/advertisment_models/ads_generic_model.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/services.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -52,8 +54,51 @@ class AdVM extends BaseVM {
String adStartDateError = "";
List<AdDetailsModel> allAds = [];
List<AdDetailsModel> adsFilteredList = [];
List<AdDetailsModel> myAds = [];
List<VehicleDamageCard> vehicleDamageCards = [];
void addNewDamagePartCard({required VehicleDamageCard damageCard}) {
vehicleDamageCards.add(damageCard);
notifyListeners();
}
void clearDamageCards() {
vehicleDamageCards.clear();
}
List<SpecialServiceCard> specialServiceCards = [];
void addNewSpecialServiceCard({required SpecialServiceCard specialServiceCard}) {
int index = vehicleAdsSpecialServices.indexWhere((element) => element.name == specialServiceCard.serviceSelectedId!.selectedOption);
if (index != -1) {
vehicleAdsSpecialServices[index].isSelected = true;
}
specialServiceCards.add(specialServiceCard);
vehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
adSpecialServiceDate = "";
notifyListeners();
}
void removeSpecialServiceCard(int index) {
String option = specialServiceCards.elementAt(index).serviceSelectedId!.selectedOption;
for (var value in vehicleAdsSpecialServices) {
if (value.name == option) {
value.isSelected = false;
break;
}
}
specialServiceCards.removeAt(index);
notifyListeners();
}
void clearSpecialServiceCard() {
specialServiceCards.clear();
}
bool isExploreAdsTapped = true;
void updateIsExploreAds(bool value) async {
@ -64,15 +109,41 @@ class AdVM extends BaseVM {
notifyListeners();
}
List<FilterListModel> adsFilterOptions = [];
populateAdsFilterList() {
adsFilterOptions.clear();
adsFilterOptions = [
FilterListModel(title: "All Ads", isSelected: true),
FilterListModel(title: "Customer Ads", isSelected: false),
FilterListModel(title: "Provider Ads", isSelected: false),
FilterListModel(title: "Mowater Ads", isSelected: false),
];
notifyListeners();
}
applyFilterOnAds({required int index}) {
if (adsFilterOptions.isEmpty) return;
for (var value in adsFilterOptions) {
value.isSelected = false;
}
adsFilterOptions[index].isSelected = true;
// TODO: --> here we will filter the allAds list
// TODO: --> and get the updated list into this new list everytime filter changes
adsFilteredList = allAds;
notifyListeners();
}
Future<void> getMyAds() async {
isFetchingLists = true;
myAds = await commonRepo.getMyAds();
myAds = await commonRepo.getAllAds(isMyAds: true);
isFetchingLists = true;
notifyListeners();
}
Future<void> getAllAds() async {
allAds = await commonRepo.getAllAds();
allAds = await commonRepo.getAllAds(isMyAds: false);
notifyListeners();
}
@ -143,6 +214,16 @@ class AdVM extends BaseVM {
notifyListeners();
}
String adSpecialServiceDate = "";
void updateAdSpecialServiceDate(String date) {
adSpecialServiceDate = date;
if (adSpecialServiceDate.isNotEmpty) {
adStartDateError = "";
}
notifyListeners();
}
SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleTypeId(SelectionModel id) async {
@ -237,10 +318,14 @@ class AdVM extends BaseVM {
notifyListeners();
}
SelectionModel vehicleDamagePartId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
// SelectionModel vehicleDamagePartId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleDamagePartId(SelectionModel id) {
vehicleDamagePartId = id;
void updateSelectionVehicleDamagePartId(SelectionModel id, int index) {
vehicleDamageCards[index].partSelectedId = id;
int partIndex = vehicleDamageParts.indexWhere((element) => element.partName == id.selectedOption);
if (partIndex != -1) {
// vehicleDamageParts[partIndex].isSelected = true;
}
notifyListeners();
}
@ -399,19 +484,31 @@ class AdVM extends BaseVM {
bool isDamagePartsValidated() {
bool isValidated = true;
if (vehicleDamagePartId.selectedId == -1) {
vehicleDamagePartId.errorValue = "Please select vehicle part";
isValidated = false;
} else {
vehicleDamagePartId.errorValue = "";
}
if (pickedDamageImages.isEmpty || pickedDamageImages.length < 3) {
vehicleDamageImageError = GlobalConsts.attachImageError;
isValidated = false;
} else {
vehicleDamageImageError = "";
}
vehicleDamageCards.forEach((element) {
if (element.partSelectedId!.selectedId == -1) {
element.partSelectedId!.errorValue = "Please select vehicle part";
isValidated = false;
} else {
element.partSelectedId!.errorValue = "";
}
});
vehicleDamageCards.forEach((element) {
if (element.partImages == null || element.partImages!.isEmpty) {
element.partImageErrorValue = GlobalConsts.attachDamagePartImage;
isValidated = false;
} else {
element.partImageErrorValue = "";
}
});
// if (pickedDamageImages.isEmpty || pickedDamageImages.length < 3) {
// vehicleDamageImageError = GlobalConsts.attachImageError;
// isValidated = false;
// } else {
// vehicleDamageImageError = "";
// }
notifyListeners();
return isValidated;
@ -492,6 +589,8 @@ class AdVM extends BaseVM {
}
Utils.hideLoading(context);
Utils.showToast("A new ads has been created.");
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
resetValues();
navigateReplaceWithName(context, AppRoutes.dashboard);
} catch (e) {
Utils.hideLoading(context);
@ -529,11 +628,16 @@ class AdVM extends BaseVM {
// sourceFlag for Camera = 0
// sourceFlag for Gallery = 1
void pickImageFromPhone(int sourceFlag) async {
File? file = await commonServices.pickImageFromPhone(1);
if (file != null) {
pickedVehicleImages.add(file);
void pickDamagePartImage(int index) async {
List<File> images = await commonServices.pickMultipleImages();
if (images.isNotEmpty) {
if (vehicleDamageCards[index].partImages == null) {
vehicleDamageCards[index].partImages = images;
} else {
vehicleDamageCards[index].partImages!.addAll(images);
}
vehicleDamageCards[index].partImageErrorValue = "";
notifyListeners();
}
}
@ -549,6 +653,31 @@ class AdVM extends BaseVM {
notifyListeners();
}
void removeDamagePartCard(int index) {
String option = vehicleDamageCards.elementAt(index).partSelectedId!.selectedOption;
for (var value in vehicleDamageParts) {
if (value.partName == option) {
value.isSelected = false;
break;
}
}
vehicleDamageCards.removeAt(index);
notifyListeners();
}
void removeDamageImageFromCard(int imageIndex, String filePath, int cardIndex) {
VehicleDamageCard card = vehicleDamageCards.elementAt(cardIndex);
if (card.partImages == null) return;
int index = card.partImages!.indexWhere((element) => element.path == filePath);
if (index == -1) {
return;
}
vehicleDamageCards[cardIndex].partImages!.removeAt(index);
notifyListeners();
}
void pickMultipleDamageImages() async {
List<File> Images = await commonServices.pickMultipleImages();
pickedDamageImages.addAll(Images);
@ -559,8 +688,29 @@ class AdVM extends BaseVM {
void resetValues() {
pickedDamageImages.clear();
pickedVehicleImages.clear();
vehicleDamageCards.clear();
specialServiceCards.clear();
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleColorId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleConditionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleMileageId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleTransmissionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleSellerTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleAdDurationId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleDemandAmount = "";
vehicleVin = "";
vehicleTitle = "";
warrantyDuration = "";
vehicleDescription = "";
selectionDurationStartDate = "";
updateFinanceAvailableStatus(false);
notifyListeners();
}
@ -573,11 +723,16 @@ class AdVM extends BaseVM {
Future<int> createNewAd() async {
AppState appState = injector.get<AppState>();
List<int> adsSelectedServices = [];
for (var value in specialServiceCards) {
adsSelectedServices.add(value.serviceSelectedId!.selectedId);
}
Ads ads = Ads(
adsDurationID: vehicleAdDurationId.selectedId,
startDate: selectionDurationStartDate,
countryId: vehicleCountryId.selectedId,
specialServiceIDs: [vehicleAdsSpecialServicesId.selectedId],
specialServiceIDs: adsSelectedServices,
);
List<VehiclePostingImages> vehicleImages = [];
pickedVehicleImages.forEach((element) async {
@ -585,10 +740,19 @@ class AdVM extends BaseVM {
});
List<VehiclePostingDamageParts> vehicleDamageImages = [];
vehicleDamageImages.add(await convertFileToVehiclePostingDamageParts(
file: pickedDamageImages.first,
damagePartId: vehicleDamagePartId.selectedId,
));
for (var card in vehicleDamageCards) {
if (card.partImages != null && card.partImages!.length > 0) {
for (var image in card.partImages!) {
VehiclePostingDamageParts stringImage = await convertFileToVehiclePostingDamageParts(
file: image,
damagePartId: card.partSelectedId!.selectedId,
);
vehicleDamageImages.add(stringImage);
}
}
}
VehiclePosting vehiclePosting = VehiclePosting(
userID: appState.getUser.data!.userInfo!.userId,
vehicleType: vehicleTypeId.selectedId,
@ -646,10 +810,41 @@ class SelectionModel {
String selectedOption;
int selectedId;
String errorValue;
String itemPrice;
SelectionModel({
this.selectedOption = "",
this.errorValue = "",
this.selectedId = 0,
this.itemPrice = "",
});
}
class VehicleDamageCard {
List<File>? partImages;
SelectionModel? partSelectedId;
String partImageErrorValue;
VehicleDamageCard({
this.partImages,
this.partSelectedId,
this.partImageErrorValue = "",
});
}
class SpecialServiceCard {
SelectionModel? serviceSelectedId;
String? serviceDate;
String? serviceDateError;
String? serviceTime;
String? serviceTimeError;
SpecialServiceCard({
this.serviceSelectedId,
this.serviceDate = "",
this.serviceDateError = "",
this.serviceTime = "",
this.serviceTimeError = "",
});
}

@ -0,0 +1,112 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/common_widgets/dotted_rect.dart';
class DottedRoundedCard extends StatelessWidget {
final Function() onTap;
final String text;
final Widget icon;
const DottedRoundedCard({Key? key, required this.onTap, required this.text, required this.icon}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
height: 120,
width: 120,
color: MyColors.white,
child: DashedRect(
color: MyColors.lightIconColor,
strokeWidth: 2.0,
gap: 4.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
icon,
SizedBox(width: 8),
text.toText(
fontSize: 15,
isBold: true,
color: MyColors.darkPrimaryColor,
),
],
),
),
),
);
}
}
class DottedRectContainer extends StatelessWidget {
final Function() onTap;
final String text;
final Widget icon;
const DottedRectContainer({Key? key, required this.onTap, required this.text, required this.icon}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
height: 46,
width: double.infinity,
color: MyColors.white,
child: DashedRect(
color: MyColors.lightIconColor,
strokeWidth: 2.0,
gap: 4.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
icon,
SizedBox(width: 8),
text.toText(
fontSize: 15,
isBold: true,
color: MyColors.darkPrimaryColor,
),
],
),
),
),
);
}
}
//
// class BuildAdStepContainer extends StatelessWidget {
// final WidgetBuilder onVehicleDetails;
// final WidgetBuilder onDamageParts;
// final WidgetBuilder onAdDuration;
// final WidgetBuilder onReviewAd;
// final AdCreationStepsEnum adCreationStepsEnum;
//
// const BuildAdStepContainer({
// Key? key,
// required this.onVehicleDetails,
// required this.onDamageParts,
// required this.onAdDuration,
// required this.onReviewAd,
// required this.adCreationStepsEnum,
// }) : super(key: key);
//
// @override
// Widget build(BuildContext context) {
// switch (adCreationStepsEnum) {
// case AdCreationStepsEnum.vehicleDetails:
// return onVehicleDetails(context);
//
// case AdCreationStepsEnum.damageParts:
// return onDamageParts(context);
//
// case AdCreationStepsEnum.adDuration:
// return onAdDuration(context);
//
// case AdCreationStepsEnum.reviewAd:
// return onReviewAd(context);
// }
// }
// }

@ -0,0 +1,141 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart';
import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
class AdDuration extends StatelessWidget {
const AdDuration({Key? key}) : super(key: key);
void onAddServiceButtonTapped(BuildContext context, AdVM adVM) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return BottomSheetServiceContent();
});
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Ad Duration".toText(fontSize: 18, isBold: true),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleAdsDurationsDrop = [];
for (var element in adVM.vehicleAdsDurations) {
vehicleAdsDurationsDrop.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateVehicleAdDurationId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
errorValue: adVM.vehicleAdDurationId.errorValue,
list: vehicleAdsDurationsDrop,
hint: "Select Duration",
dropdownValue: adVM.vehicleAdDurationId.selectedId != -1 ? DropValue(adVM.vehicleAdDurationId.selectedId, adVM.vehicleAdDurationId.selectedOption, "") : null,
);
}),
8.height,
TxtField(
errorValue: adVM.adStartDateError,
hint: 'Start Date',
value: adVM.selectionDurationStartDate,
isNeedClickAll: true,
postfixData: Icons.calendar_month_rounded,
postFixDataColor: MyColors.darkTextColor,
onTap: () async {
final formattedDate = await Utils.pickDateFromDatePicker(context);
adVM.updateSelectionDurationStartDate(formattedDate);
},
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Select Special Services".toText(fontSize: 18, isBold: true),
8.height,
CustomAddButton(
onTap: () {
onAddServiceButtonTapped(context, adVM);
},
text: "Add Service",
icon: Container(
height: 24,
width: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: Icon(
Icons.add,
color: MyColors.white,
),
),
),
20.height,
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: adVM.specialServiceCards.length,
itemBuilder: (BuildContext context, int index) {
SpecialServiceCard specialServicesCard = adVM.specialServiceCards[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 18, isBold: true),
),
InkWell(
onTap: () => adVM.removeSpecialServiceCard(index),
child: Icon(Icons.delete_outline_rounded),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"12 July, 2023 - 09:30AM".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 14),
],
),
],
),
5.height,
Divider(thickness: 1.5)
],
),
10.height,
],
);
},
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)),
],
);
},
);
}
}

@ -0,0 +1,250 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/picked_images_container.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class ReviewAd extends StatelessWidget {
const ReviewAd({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
VehicleDetailsReview(),
DamagePartsReview(),
AdDurationReview(),
],
);
}
}
class SingleDetailWidget extends StatelessWidget {
final String text;
final String type;
const SingleDetailWidget({Key? key, required this.text, required this.type}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"$type:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
text.toText(fontSize: 14, color: MyColors.black, isBold: true),
],
);
}
}
class VehicleDetailsReview extends StatelessWidget {
const VehicleDetailsReview({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Details".toText(fontSize: 18, isBold: true),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: adVM.vehicleTypeId.selectedOption, type: "Vehicle Type"),
16.height,
SingleDetailWidget(text: adVM.vehicleModelYearId.selectedOption, type: "Vehicle Year"),
16.height,
SingleDetailWidget(text: adVM.vehicleConditionId.selectedOption, type: "Vehicle Condition"),
16.height,
SingleDetailWidget(text: adVM.vehicleMileageId.selectedOption, type: "Vehicle Mileage"),
16.height,
SingleDetailWidget(text: adVM.vehicleSellerTypeId.selectedOption, type: "Seller Type"),
16.height,
SingleDetailWidget(text: adVM.vehicleCityId.selectedOption, type: "Vehicle City"),
16.height,
SingleDetailWidget(text: adVM.vehicleVin, type: "Vehicle VIN"),
16.height,
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: adVM.vehicleModelId.selectedOption, type: "Vehicle Model"),
16.height,
SingleDetailWidget(text: adVM.vehicleColorId.selectedOption, type: "Vehicle Color"),
16.height,
SingleDetailWidget(text: adVM.vehicleCategoryId.selectedOption, type: "Vehicle Category"),
16.height,
SingleDetailWidget(text: adVM.vehicleTransmissionId.selectedOption, type: "Vehicle Transmission"),
16.height,
SingleDetailWidget(text: adVM.vehicleCountryId.selectedOption, type: "Vehicle Country"),
16.height,
SingleDetailWidget(text: adVM.vehicleDemandAmount, type: "Vehicle Amount"),
16.height,
SingleDetailWidget(text: adVM.vehicleTitle, type: "Vehicle Title"),
16.height,
],
),
),
],
),
SingleDetailWidget(text: adVM.warrantyDuration, type: "Warranty Available"),
8.height,
SingleDetailWidget(text: adVM.vehicleDescription, type: "Description"),
8.height,
SingleDetailWidget(text: adVM.financeAvailableStatus ? "Yes" : "No", type: "Finance Available"),
8.height,
"Vehicle Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
if (adVM.pickedVehicleImages.isNotEmpty) ...[
// 10.height,
PickedImagesContainer(
pickedImages: adVM.pickedVehicleImages,
onCrossPressedPrimary: adVM.removeImageFromList,
isReview: true,
onAddImagePressed: () {},
),
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class DamagePartsReview extends StatelessWidget {
const DamagePartsReview({Key? key}) : super(key: key);
Widget buildDamagePartList(AdVM adVM) {
List<Widget> list = List.generate(
adVM.vehicleDamageCards.length,
(index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
8.height,
Row(
children: [
SingleDetailWidget(type: "Vehicle Part", text: adVM.vehicleDamageCards[index].partSelectedId!.selectedOption),
],
),
if (adVM.vehicleDamageCards[index].partImages != null && adVM.vehicleDamageCards[index].partImages!.isNotEmpty) ...[
"Damage Part Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
PickedImagesContainer(
pickedImages: adVM.vehicleDamageCards[index].partImages!,
onCrossPressedPrimary: adVM.removeImageFromList,
isReview: true,
onAddImagePressed: () {},
),
],
Divider(thickness: 2),
],
));
return Column(
children: list,
);
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Damage Part".toText(fontSize: 18, isBold: true),
buildDamagePartList(adVM),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class AdDurationReview extends StatelessWidget {
const AdDurationReview({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Ad Duration".toText(fontSize: 18, isBold: true),
8.height,
Row(
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(type: "Duration", text: adVM.vehicleAdDurationId.selectedOption),
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(type: "Start Date", text: adVM.selectionDurationStartDate),
],
),
),
],
),
if (adVM.specialServiceCards.isNotEmpty) ...[
15.height,
"Special Services".toText(fontSize: 18, isBold: true),
ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Row(
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
8.height,
SingleDetailWidget(type: "Special Service", text: adVM.specialServiceCards[index].serviceSelectedId!.selectedOption),
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(type: "Amount", text: adVM.specialServiceCards[index].serviceSelectedId!.itemPrice),
],
),
),
],
);
},
separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
itemCount: adVM.specialServiceCards.length)
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}

@ -0,0 +1,139 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart';
import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
import 'package:mc_common_app/views/advertisement/picked_images_container.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class DamageParts extends StatelessWidget {
const DamageParts({Key? key}) : super(key: key);
bool getEnabledStatus(bool? isSelected) {
if (isSelected == null) {
return true;
}
if (isSelected) {
return false;
}
return true;
}
void onAddButtonTapped(BuildContext context, AdVM adVM) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return BottomSheetListContent(adVM: adVM);
});
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomAddButton(
onTap: () {
onAddButtonTapped(context, adVM);
},
text: "Add Damage Part",
icon: Container(
height: 24,
width: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: Icon(
Icons.add,
color: MyColors.white,
),
)).horPaddingMain(),
9.height,
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: adVM.vehicleDamageCards.length,
itemBuilder: (BuildContext context, int index) {
VehicleDamageCard vehicleDamageCard = adVM.vehicleDamageCards[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
vehicleDamageCard.partSelectedId!.selectedOption.toText(fontSize: 18, isBold: true),
InkWell(onTap: () => adVM.removeDamagePartCard(index), child: Icon(Icons.delete_outline_rounded)),
],
),
10.height,
// Builder(builder: (context) {
// List<DropValue> vehicleDamagePartsDrop = [];
// for (var element in adVM.vehicleDamageParts) {
// vehicleDamagePartsDrop.add(DropValue(
// element.id?.toInt() ?? 0,
// element.partName ?? "",
// "",
// isEnabled: true,
// ));
// }
// return DropdownField((DropValue value) {
// adVM.updateSelectionVehicleDamagePartId(SelectionModel(selectedOption: value.value, selectedId: value.id), index);
// },
// dropdownValue: adVM.vehicleDamageCards[index].partSelectedId!.selectedId != -1
// ? DropValue(adVM.vehicleDamageCards[index].partSelectedId!.selectedId, adVM.vehicleDamageCards[index].partSelectedId!.selectedOption, "")
// : null,
// list: vehicleDamagePartsDrop,
// hint: "Vehicle Part",
// errorValue: adVM.vehicleDamageCards[index].partSelectedId!.errorValue);
// }),
// 8.height,
// vehicleDamageCard.partImages != null ?
PickedImagesContainer(
pickedImages: vehicleDamageCard.partImages ?? [],
onCrossPressedSecondary: (imageIndex, filePath) {
adVM.removeDamageImageFromCard(imageIndex, filePath, index);
},
index: index,
onAddImagePressed: () {
context.read<AdVM>().pickDamagePartImage(index);
},
),
// : SizedBox(),
// vehicleDamageCard.partImages == null || vehicleDamageCard.partImages!.length < 10
// ? DottedRectContainer(
// onTap: () => context.read<AdVM>().pickDamagePartImage(index),
// text: "Add part image",
// icon: MyAssets.attachmentIcon.buildSvg(),
// )
// : SizedBox(),
vehicleDamageCard.partImages != null ? 0.height : 8.height,
if (vehicleDamageCard.partImageErrorValue != "") ...[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
vehicleDamageCard.partImageErrorValue.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
),
// DottedRectContainer(
// onTap: () => adVM.addNewDamagePartCard(
// damageCard: VehicleDamageCard(partImageErrorValue: "", partImages: null, partSelectedId: SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""))),
// text: "Add Part",
// icon: MyAssets.attachmentIcon.buildSvg(),
// ).paddingOnly(right: 21, left: 21, top: 10, bottom: 10),
],
);
},
);
}
}

@ -0,0 +1,290 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/picked_images_container.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
class VehicleDetails extends StatelessWidget {
const VehicleDetails({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Detail".toText(fontSize: 18, isBold: true),
8.height,
Builder(
builder: (BuildContext context) {
List<DropValue> vehicleTypesDrop = [];
for (var element in adVM.vehicleTypes) {
vehicleTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value, errorValue: "")),
list: vehicleTypesDrop,
dropdownValue: adVM.vehicleTypeId.selectedId != -1 ? DropValue(adVM.vehicleTypeId.selectedId, adVM.vehicleTypeId.selectedOption, "") : null,
errorValue: adVM.vehicleTypeId.errorValue,
hint: "Vehicle Type",
);
},
),
if (adVM.vehicleTypeId.selectedId != -1) ...[
if (adVM.isFetchingLists) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(),
],
).paddingAll(10),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in adVM.vehicleModels) {
vehicleModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.model ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue: adVM.vehicleModelId.selectedId != -1 ? DropValue(adVM.vehicleModelId.selectedId, adVM.vehicleModelId.selectedOption, "") : null,
hint: "Vehicle Model",
errorValue: adVM.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element in adVM.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue: adVM.vehicleModelYearId.selectedId != -1 ? DropValue(adVM.vehicleModelYearId.selectedId, adVM.vehicleModelYearId.selectedOption, "") : null,
hint: "Vehicle Model Year",
errorValue: adVM.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleColorsDrop = [];
for (var element in adVM.vehicleColors) {
vehicleColorsDrop.add(DropValue(element.id?.toInt() ?? 0, element.color ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleColorId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleColorsDrop,
hint: "Vehicle Color",
dropdownValue: adVM.vehicleColorId.selectedId != -1 ? DropValue(adVM.vehicleColorId.selectedId, adVM.vehicleColorId.selectedOption, "") : null,
errorValue: adVM.vehicleColorId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleConditionsDrop = [];
for (var element in adVM.vehicleConditions) {
vehicleConditionsDrop.add(DropValue(element.id?.toInt() ?? 0, element.condition ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleConditionsDrop,
dropdownValue: adVM.vehicleConditionId.selectedId != -1 ? DropValue(adVM.vehicleConditionId.selectedId, adVM.vehicleConditionId.selectedOption, "") : null,
hint: "Vehicle Condition",
errorValue: adVM.vehicleConditionId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCategoriesDrop = [];
for (var element in adVM.vehicleCategories) {
vehicleCategoriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.category ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCategoriesDrop,
hint: "Vehicle Category",
dropdownValue: adVM.vehicleCategoryId.selectedId != -1 ? DropValue(adVM.vehicleCategoryId.selectedId, adVM.vehicleCategoryId.selectedOption, "") : null,
errorValue: adVM.vehicleCategoryId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleMileageDrop = [];
for (var element in adVM.vehicleMileages) {
vehicleMileageDrop.add(DropValue(element.id?.toInt() ?? 0, "${element.mileageStart ?? ""} - ${element.mileageEnd ?? ""}", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleMileageId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleMileageDrop,
dropdownValue: adVM.vehicleMileageId.selectedId != -1 ? DropValue(adVM.vehicleMileageId.selectedId, adVM.vehicleMileageId.selectedOption, "") : null,
hint: "Vehicle Mileage",
errorValue: adVM.vehicleMileageId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleTransmissionsDrop = [];
for (var element in adVM.vehicleTransmissions) {
vehicleTransmissionsDrop.add(DropValue(element.id?.toInt() ?? 0, element.transmission ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleTransmissionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTransmissionsDrop,
hint: "Vehicle Transmission",
errorValue: adVM.vehicleTransmissionId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleSellerTypesDrop = [];
for (var element in adVM.vehicleSellerTypes) {
vehicleSellerTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.sellerType ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleSellerTypesDrop,
dropdownValue: adVM.vehicleSellerTypeId.selectedId != -1 ? DropValue(adVM.vehicleSellerTypeId.selectedId, adVM.vehicleSellerTypeId.selectedOption, "") : null,
hint: "Vehicle Seller Type",
errorValue: adVM.vehicleSellerTypeId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in adVM.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.countryName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue: adVM.vehicleCountryId.selectedId != -1 ? DropValue(adVM.vehicleCountryId.selectedId, adVM.vehicleCountryId.selectedOption, "") : null,
hint: "Vehicle Country",
errorValue: adVM.vehicleCountryId.errorValue,
);
}),
if (adVM.vehicleCountryId.selectedId != -1) ...[
if (adVM.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element in adVM.vehicleCities) {
vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: adVM.vehicleCityId.selectedId != -1 ? DropValue(adVM.vehicleCityId.selectedId, adVM.vehicleCityId.selectedOption, "") : null,
hint: "Vehicle City",
errorValue: adVM.vehicleCityId.errorValue,
);
}),
],
],
8.height,
TxtField(
value: adVM.vehicleDemandAmount,
errorValue: adVM.demandAmountError,
hint: "Demand Amount",
onChanged: (v) => adVM.updateVehicleDemandAmount(v),
),
8.height,
TxtField(
value: adVM.vehicleVin,
errorValue: adVM.vehicleVinError,
hint: "Vehicle VIN",
onChanged: (v) => adVM.updateVehicleVin(v),
),
8.height,
TxtField(
value: adVM.vehicleTitle,
errorValue: adVM.vehicleTitleError,
hint: "Vehicle Title",
onChanged: (v) => adVM.updateVehicleTitle(v),
),
8.height,
TxtField(
value: adVM.warrantyDuration,
errorValue: adVM.warrantyError,
hint: "Warranty Available (No. of Years)",
onChanged: (v) => adVM.updateVehicleWarrantyDuration(v),
),
8.height,
TxtField(
value: adVM.vehicleDescription,
hint: "Vehicle Description",
maxLines: 5,
errorValue: adVM.vehicleDescError,
onChanged: (v) => adVM.updateVehicleDescription(v),
),
22.height,
"Finance Available".toText(fontSize: 16),
8.height,
Container(
width: 65,
height: 37,
decoration: BoxDecoration(
color: adVM.financeAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white,
borderRadius: BorderRadius.circular(25.0),
border: Border.all(color: MyColors.black, width: 1.5),
),
child: CupertinoSwitch(
activeColor: MyColors.darkPrimaryColor,
trackColor: MyColors.white,
thumbColor: MyColors.grey98Color,
value: adVM.financeAvailableStatus,
onChanged: (value) {
adVM.updateFinanceAvailableStatus(value);
},
),
),
28.height,
"Vehicle Pictures".toText(fontSize: 18, isBold: true),
8.height,
DottedRectContainer(
onTap: () => context.read<AdVM>().pickMultipleImages(),
text: "Attach Image",
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (adVM.vehicleImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
adVM.vehicleImageError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
if (adVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedImagesContainer(
pickedImages: adVM.pickedVehicleImages,
onCrossPressedPrimary: adVM.removeImageFromList,
onAddImagePressed: () {
context.read<AdVM>().pickMultipleImages();
},
),
],
15.height,
],
]
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
});
}
}

@ -1,667 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.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/views/advertisement/picked_images_container.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
import 'package:mc_common_app/widgets/common_widgets/dotted_rect.dart';
class AttachImageContainer extends StatelessWidget {
final Function() onTap;
const AttachImageContainer({Key? key, required this.onTap}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
height: 46,
width: double.infinity,
color: MyColors.white,
child: DashedRect(
color: MyColors.lightIconColor,
strokeWidth: 2.0,
gap: 4.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyAssets.attachmentIcon.buildSvg(),
"Attach Image".toText(
fontSize: 15,
isBold: true,
color: MyColors.darkPrimaryColor,
),
],
),
),
),
);
}
}
class BuildAdStepContainer extends StatelessWidget {
final WidgetBuilder onVehicleDetails;
final WidgetBuilder onDamageParts;
final WidgetBuilder onAdDuration;
final WidgetBuilder onReviewAd;
final AdCreationStepsEnum adCreationStepsEnum;
const BuildAdStepContainer({
Key? key,
required this.onVehicleDetails,
required this.onDamageParts,
required this.onAdDuration,
required this.onReviewAd,
required this.adCreationStepsEnum,
}) : super(key: key);
@override
Widget build(BuildContext context) {
switch (adCreationStepsEnum) {
case AdCreationStepsEnum.vehicleDetails:
return onVehicleDetails(context);
case AdCreationStepsEnum.damageParts:
return onDamageParts(context);
case AdCreationStepsEnum.adDuration:
return onAdDuration(context);
case AdCreationStepsEnum.reviewAd:
return onReviewAd(context);
}
}
}
class VehicleDetails extends StatelessWidget {
const VehicleDetails({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Detail".toText(fontSize: 18, isBold: true),
8.height,
Builder(
builder: (BuildContext context) {
List<DropValue> vehicleTypesDrop = [];
for (var element in adVM.vehicleTypes) {
vehicleTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value, errorValue: "")),
list: vehicleTypesDrop,
dropdownValue: adVM.vehicleTypeId.selectedId != -1 ? DropValue(adVM.vehicleTypeId.selectedId, adVM.vehicleTypeId.selectedOption, "") : null,
errorValue: adVM.vehicleTypeId.errorValue,
hint: "Vehicle Type",
);
},
),
if (adVM.vehicleTypeId.selectedId != -1) ...[
if (adVM.isFetchingLists) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(),
],
).paddingAll(10),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in adVM.vehicleModels) {
vehicleModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.model ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue: adVM.vehicleModelId.selectedId != -1 ? DropValue(adVM.vehicleModelId.selectedId, adVM.vehicleModelId.selectedOption, "") : null,
hint: "Vehicle Model",
errorValue: adVM.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element in adVM.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue: adVM.vehicleModelYearId.selectedId != -1 ? DropValue(adVM.vehicleModelYearId.selectedId, adVM.vehicleModelYearId.selectedOption, "") : null,
hint: "Vehicle Model Year",
errorValue: adVM.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleColorsDrop = [];
for (var element in adVM.vehicleColors) {
vehicleColorsDrop.add(DropValue(element.id?.toInt() ?? 0, element.color ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleColorId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleColorsDrop,
hint: "Vehicle Color",
dropdownValue: adVM.vehicleColorId.selectedId != -1 ? DropValue(adVM.vehicleColorId.selectedId, adVM.vehicleColorId.selectedOption, "") : null,
errorValue: adVM.vehicleColorId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleConditionsDrop = [];
for (var element in adVM.vehicleConditions) {
vehicleConditionsDrop.add(DropValue(element.id?.toInt() ?? 0, element.condition ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleConditionsDrop,
dropdownValue: adVM.vehicleConditionId.selectedId != -1 ? DropValue(adVM.vehicleConditionId.selectedId, adVM.vehicleConditionId.selectedOption, "") : null,
hint: "Vehicle Condition",
errorValue: adVM.vehicleConditionId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCategoriesDrop = [];
for (var element in adVM.vehicleCategories) {
vehicleCategoriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.category ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCategoriesDrop,
hint: "Vehicle Category",
dropdownValue: adVM.vehicleCategoryId.selectedId != -1 ? DropValue(adVM.vehicleCategoryId.selectedId, adVM.vehicleCategoryId.selectedOption, "") : null,
errorValue: adVM.vehicleCategoryId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleMileageDrop = [];
for (var element in adVM.vehicleMileages) {
vehicleMileageDrop.add(DropValue(element.id?.toInt() ?? 0, "${element.mileageStart ?? ""} - ${element.mileageEnd ?? ""}", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleMileageId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleMileageDrop,
dropdownValue: adVM.vehicleMileageId.selectedId != -1 ? DropValue(adVM.vehicleMileageId.selectedId, adVM.vehicleMileageId.selectedOption, "") : null,
hint: "Vehicle Mileage",
errorValue: adVM.vehicleMileageId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleTransmissionsDrop = [];
for (var element in adVM.vehicleTransmissions) {
vehicleTransmissionsDrop.add(DropValue(element.id?.toInt() ?? 0, element.transmission ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleTransmissionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTransmissionsDrop,
hint: "Vehicle Transmission",
errorValue: adVM.vehicleTransmissionId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleSellerTypesDrop = [];
for (var element in adVM.vehicleSellerTypes) {
vehicleSellerTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.sellerType ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleSellerTypesDrop,
dropdownValue: adVM.vehicleSellerTypeId.selectedId != -1 ? DropValue(adVM.vehicleSellerTypeId.selectedId, adVM.vehicleSellerTypeId.selectedOption, "") : null,
hint: "Vehicle Seller Type",
errorValue: adVM.vehicleSellerTypeId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in adVM.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.countryName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue: adVM.vehicleCountryId.selectedId != -1 ? DropValue(adVM.vehicleCountryId.selectedId, adVM.vehicleCountryId.selectedOption, "") : null,
hint: "Vehicle Country",
errorValue: adVM.vehicleCountryId.errorValue,
);
}),
if (adVM.vehicleCountryId.selectedId != -1) ...[
if (adVM.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element in adVM.vehicleCities) {
vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: adVM.vehicleCityId.selectedId != -1 ? DropValue(adVM.vehicleCityId.selectedId, adVM.vehicleCityId.selectedOption, "") : null,
hint: "Vehicle City",
errorValue: adVM.vehicleCityId.errorValue,
);
}),
],
],
8.height,
TxtField(
value: adVM.vehicleDemandAmount,
errorValue: adVM.demandAmountError,
hint: "Demand Amount",
onChanged: (v) => adVM.updateVehicleDemandAmount(v),
),
8.height,
TxtField(
value: adVM.vehicleVin,
errorValue: adVM.vehicleVinError,
hint: "Vehicle VIN",
onChanged: (v) => adVM.updateVehicleVin(v),
),
8.height,
TxtField(
value: adVM.vehicleTitle,
errorValue: adVM.vehicleTitleError,
hint: "Vehicle Title",
onChanged: (v) => adVM.updateVehicleTitle(v),
),
8.height,
TxtField(
value: adVM.warrantyDuration,
errorValue: adVM.warrantyError,
hint: "Warranty Available (No. of Years)",
onChanged: (v) => adVM.updateVehicleWarrantyDuration(v),
),
8.height,
TxtField(
value: adVM.vehicleDescription,
hint: "Vehicle Description",
maxLines: 5,
errorValue: adVM.vehicleDescError,
onChanged: (v) => adVM.updateVehicleDescription(v),
),
22.height,
"Finance Available".toText(fontSize: 16),
8.height,
Container(
width: 65,
height: 37,
decoration: BoxDecoration(
color: adVM.financeAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white,
borderRadius: BorderRadius.circular(25.0),
border: Border.all(color: MyColors.black, width: 1.5),
),
child: CupertinoSwitch(
activeColor: MyColors.darkPrimaryColor,
trackColor: MyColors.white,
thumbColor: MyColors.grey98Color,
value: adVM.financeAvailableStatus,
onChanged: (value) {
adVM.updateFinanceAvailableStatus(value);
},
),
),
28.height,
"Vehicle Pictures".toText(fontSize: 18, isBold: true),
8.height,
AttachImageContainer(onTap: () {
context.read<AdVM>().pickMultipleImages();
}),
if (adVM.vehicleImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
adVM.vehicleImageError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
if (adVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedImagesContainer(
pickedImages: adVM.pickedVehicleImages,
onCrossPressed: adVM.removeImageFromList,
),
],
15.height,
],
]
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
});
}
}
class DamageParts extends StatelessWidget {
const DamageParts({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Damage Pictures".toText(fontSize: 18, isBold: true),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleDamagePartsDrop = [];
for (var element in adVM.vehicleDamageParts) {
vehicleDamagePartsDrop.add(DropValue(element.id?.toInt() ?? 0, element.partName ?? "", ""));
}
return DropdownField(
(DropValue value) {
adVM.updateSelectionVehicleDamagePartId(SelectionModel(selectedOption: value.value, selectedId: value.id));
},
dropdownValue: adVM.vehicleDamagePartId.selectedId != -1 ? DropValue(adVM.vehicleDamagePartId.selectedId, adVM.vehicleDamagePartId.selectedOption, "") : null,
list: vehicleDamagePartsDrop,
hint: "Vehicle Part",
errorValue: adVM.vehicleDamagePartId.errorValue,
);
}),
8.height,
AttachImageContainer(onTap: () {
adVM.pickMultipleDamageImages();
}),
if (adVM.vehicleDamageImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
adVM.vehicleDamageImageError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
if (adVM.pickedDamageImages.isNotEmpty) ...[
16.height,
PickedImagesContainer(
pickedImages: adVM.pickedDamageImages,
onCrossPressed: adVM.removeDamageImageFromList,
),
],
20.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class AdDuration extends StatelessWidget {
const AdDuration({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Ad Duration".toText(fontSize: 18, isBold: true),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleAdsDurationsDrop = [];
for (var element in adVM.vehicleAdsDurations) {
vehicleAdsDurationsDrop.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateVehicleAdDurationId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
errorValue: adVM.vehicleAdDurationId.errorValue,
list: vehicleAdsDurationsDrop,
hint: "Select Duration",
);
}),
8.height,
TxtField(
errorValue: adVM.adStartDateError,
hint: 'Start Date',
value: adVM.selectionDurationStartDate,
isNeedClickAll: true,
postfixData: Icons.calendar_month_rounded,
postFixDataColor: MyColors.lightTextColor,
onTap: () async {
final formattedDate = await Utils.pickDateFromDatePicker(context);
adVM.updateSelectionDurationStartDate(formattedDate);
},
),
28.height,
"Select Special Services".toText(fontSize: 18, isBold: true),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleAdsSpecialServices = [];
for (var element in adVM.vehicleAdsSpecialServices) {
vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleAdsSpecialServices,
hint: "Select Service",
);
}),
20.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class SingleDetailWidget extends StatelessWidget {
final String text;
final String type;
const SingleDetailWidget({Key? key, required this.text, required this.type}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"$type:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
text.toText(fontSize: 14, color: MyColors.black, isBold: true),
],
);
}
}
class ReviewAd extends StatelessWidget {
const ReviewAd({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
VehicleDetailsReview(),
DamagePartsReview(),
AdDurationReview(),
],
);
}
}
class VehicleDetailsReview extends StatelessWidget {
const VehicleDetailsReview({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Details".toText(fontSize: 18, isBold: true),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: adVM.vehicleTypeId.selectedOption, type: "Vehicle Type"),
16.height,
SingleDetailWidget(text: adVM.vehicleModelYearId.selectedOption, type: "Vehicle Year"),
16.height,
SingleDetailWidget(text: adVM.vehicleConditionId.selectedOption, type: "Vehicle Condition"),
16.height,
SingleDetailWidget(text: adVM.vehicleMileageId.selectedOption, type: "Vehicle Mileage"),
16.height,
SingleDetailWidget(text: adVM.vehicleSellerTypeId.selectedOption, type: "Seller Type"),
16.height,
SingleDetailWidget(text: adVM.vehicleCityId.selectedOption, type: "Vehicle City"),
16.height,
SingleDetailWidget(text: adVM.vehicleVin, type: "Vehicle VIN"),
16.height,
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: adVM.vehicleModelId.selectedOption, type: "Vehicle Model"),
16.height,
SingleDetailWidget(text: adVM.vehicleColorId.selectedOption, type: "Vehicle Color"),
16.height,
SingleDetailWidget(text: adVM.vehicleCategoryId.selectedOption, type: "Vehicle Category"),
16.height,
SingleDetailWidget(text: adVM.vehicleTransmissionId.selectedOption, type: "Vehicle Transmission"),
16.height,
SingleDetailWidget(text: adVM.vehicleCountryId.selectedOption, type: "Vehicle Country"),
16.height,
SingleDetailWidget(text: adVM.vehicleDemandAmount, type: "Vehicle Amount"),
16.height,
SingleDetailWidget(text: adVM.vehicleTitle, type: "Vehicle Title"),
16.height,
],
),
),
],
),
SingleDetailWidget(text: adVM.warrantyDuration, type: "Warranty Available"),
8.height,
SingleDetailWidget(text: adVM.vehicleDescription, type: "Description"),
8.height,
SingleDetailWidget(text: adVM.financeAvailableStatus ? "Yes" : "No", type: "Finance Available"),
8.height,
"Vehicle Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
if (adVM.pickedVehicleImages.isNotEmpty) ...[
// 10.height,
PickedImagesContainer(
pickedImages: adVM.pickedVehicleImages,
onCrossPressed: adVM.removeImageFromList,
),
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class DamagePartsReview extends StatelessWidget {
const DamagePartsReview({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Damage Part".toText(fontSize: 18, isBold: true),
8.height,
Row(
children: [
SingleDetailWidget(type: "Vehicle Part", text: adVM.vehicleDamagePartId.selectedOption),
],
),
8.height,
"Damage Part Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
if (adVM.pickedDamageImages.isNotEmpty) ...[
// 16.height,
PickedImagesContainer(
pickedImages: adVM.pickedDamageImages,
onCrossPressed: adVM.removeDamageImageFromList,
),
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}
class AdDurationReview extends StatelessWidget {
const AdDurationReview({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Damage Part".toText(fontSize: 18, isBold: true),
8.height,
Row(
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(type: "Duration", text: adVM.vehicleAdDurationId.selectedOption),
8.height,
SingleDetailWidget(type: "Special Service", text: adVM.vehicleAdsSpecialServicesId.selectedOption),
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(type: "Start Date", text: adVM.selectionDurationStartDate),
],
),
),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
);
}
}

@ -1,10 +1,10 @@
import 'package:mc_common_app/views/advertisement/ads_images_slider.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/views/advertisement/ads_images_slider.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -67,7 +67,7 @@ class AdsDetailView extends StatelessWidget {
),
],
),
"${adDetails.createdOn}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) : SizedBox(),
],
),
Row(

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/theme/colors.dart';

@ -101,9 +101,11 @@ class AdCard extends StatelessWidget {
(adDetails.vehicle!.cityName ?? "").toText(
color: MyColors.lightTextColor,
),
"9 Hours Ago".toText(
color: MyColors.lightTextColor,
),
adDetails.createdOn != null
? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(
color: MyColors.lightTextColor,
)
: SizedBox(),
],
),
],

@ -0,0 +1,262 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
class BottomSheetListContent extends StatefulWidget {
final AdVM adVM;
const BottomSheetListContent({Key? key, required this.adVM}) : super(key: key);
@override
State<BottomSheetListContent> createState() => _BottomSheetListContentState();
}
class _BottomSheetListContentState extends State<BottomSheetListContent> {
bool checkBoxValue = false;
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.85,
child: Column(
children: [
Container(
margin: const EdgeInsets.all(8),
height: 8,
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
12.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Damage Part List".toText(fontSize: 24, isBold: true),
],
),
8.height,
TxtField(
value: "",
errorValue: "",
hint: "Search Part",
onChanged: (value) {},
),
8.height,
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.adVM.vehicleDamageParts.length,
itemBuilder: (BuildContext context, int index) {
VehiclePartModel vehiclePart = widget.adVM.vehicleDamageParts[index];
return Column(
children: [
// CheckboxListTile(
// value: false,
// visualDensity: VisualDensity.compact,
// contentPadding: EdgeInsets.zero,
// controlAffinity: ListTileControlAffinity.leading,
// title: "Rear Break Light".toText(
// fontSize: 16,
// isBold: true,
// ),
// onChanged: (value) {},
// ),
InkWell(
onTap: () {
if (vehiclePart.isSelected!) {
return;
}
widget.adVM.vehicleDamageParts[index].isChecked = !(widget.adVM.vehicleDamageParts[index].isChecked!);
setState(() {});
},
child: Row(
children: [
SizedBox(
height: 40.0,
width: 30.0,
child: Transform.scale(
scale: 1.3,
child: Checkbox(
value: vehiclePart.isSelected! ? true : vehiclePart.isChecked,
activeColor: vehiclePart.isSelected! ? MyColors.lightTextColor : MyColors.primaryColor,
onChanged: (value) {},
),
),
),
const SizedBox(width: 20),
vehiclePart.partName.toString().toText(
fontSize: 16,
isBold: true,
color: vehiclePart.isSelected! ? MyColors.lightTextColor : MyColors.black,
)
],
),
),
const Divider(thickness: 1),
],
);
},
),
),
SizedBox(
width: double.infinity,
child: ShowFillButton(
title: "Add Damage Part",
onPressed: () {
for (var value in widget.adVM.vehicleDamageParts) {
if (value.isChecked! && !value.isSelected!) {
widget.adVM.addNewDamagePartCard(
damageCard: VehicleDamageCard(
partImageErrorValue: "",
partImages: null,
partSelectedId: SelectionModel(selectedOption: value.partName!, selectedId: value.id!, errorValue: ""),
),
);
value.isChecked = false;
value.isSelected = true;
}
}
Navigator.pop(context);
},
).paddingOnly(bottom: 10),
),
],
),
).horPaddingMain();
}
}
class BottomSheetServiceContent extends StatelessWidget {
const BottomSheetServiceContent({Key? key}) : super(key: key);
bool isButtonTappable(AdVM adVM) {
bool status = (adVM.vehicleAdsSpecialServicesId.selectedId != -1) && (adVM.vehicleAdsSpecialServicesId.selectedOption != "");
if (status) {
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.85,
child: Column(
children: [
Container(
margin: const EdgeInsets.all(8),
height: 8,
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
12.height,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Add Special Service".toText(fontSize: 24, isBold: true),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleAdsSpecialServices = [];
for (var element in adVM.vehicleAdsSpecialServices) {
if (!element.isSelected!) {
vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", element.price == null ? "" : element.price!.toInt().toString()));
}
}
return DropdownField(
(DropValue value) => adVM.updateVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: vehicleAdsSpecialServices,
hint: "Select Service",
dropdownValue:
adVM.vehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.vehicleAdsSpecialServicesId.selectedId, adVM.vehicleAdsSpecialServicesId.selectedOption, "") : null,
);
}),
8.height,
TxtField(
errorValue: adVM.adStartDateError,
hint: 'Date',
value: adVM.adSpecialServiceDate,
isNeedClickAll: true,
postfixData: Icons.calendar_month_rounded,
postFixDataColor: MyColors.lightTextColor,
onTap: () async {
final formattedDate = await Utils.pickDateFromDatePicker(context);
adVM.updateAdSpecialServiceDate(formattedDate);
},
),
22.height,
"Available slots".toText(fontSize: 15, isBold: true),
8.height,
const BuildTimeSlots(),
22.height,
"Service Amount".toText(fontSize: 16, isBold: true, color: MyColors.lightTextColor),
if (adVM.vehicleAdsSpecialServicesId.selectedId != -1) ...[
adVM.vehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true),
"SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
// 5.height,
// Divider(thickness: 1.2),
// 5.height,
// DottedRectContainer(
// onTap: () => null,
// text: "Add Service",
// icon: MyAssets.attachmentIcon.buildSvg(),
// ),
],
),
),
SizedBox(
width: double.infinity,
child: ShowFillButton(
backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor : MyColors.primaryColor,
title: "Add Service",
onPressed: () {
if (!isButtonTappable(adVM)) {
return;
}
Navigator.pop(context);
adVM.addNewSpecialServiceCard(
specialServiceCard: SpecialServiceCard(
serviceDate: "",
serviceDateError: "",
serviceSelectedId: adVM.vehicleAdsSpecialServicesId,
serviceTimeError: "",
serviceTime: "",
),
);
// for (var value in widget.adVM.vehicleDamageParts) {
// if (value.isChecked! && !value.isSelected!) {
// widget.adVM.addNewDamagePartCard(
// damageCard: VehicleDamageCard(
// partImageErrorValue: "",
// partImages: null,
// partSelectedId: SelectionModel(selectedOption: value.partName!, selectedId: value.id!, errorValue: ""),
// ),
// );
// value.isChecked = false;
// value.isSelected = true;
// }
// }
},
).paddingOnly(bottom: 10),
),
],
).horPaddingMain(),
);
},
);
}
}

@ -1,10 +1,10 @@
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
@ -25,7 +25,9 @@ class CreateAdProgressSteps extends StatelessWidget {
color: isSelected ? MyColors.darkPrimaryColor : MyColors.lightIconColor,
),
),
child: icon.buildSvg(color: isSelected ? MyColors.white : MyColors.lightIconColor,),
child: icon.buildSvg(
color: isSelected ? MyColors.white : MyColors.lightIconColor,
),
),
5.height,
title.toText(

@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps_containers.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';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/damage_parts_container.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/vehicle_details_container.dart';
import 'package:mc_common_app/views/advertisement/create_ad_progress_steps.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
class CustomAddButton extends StatelessWidget {
final Widget icon;
final String text;
final Function() onTap;
const CustomAddButton({Key? key, required this.text, required this.onTap, required this.icon}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
height: 86,
decoration: BoxDecoration(border: Border.all(width: 2, color: MyColors.primaryColor)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
icon,
SizedBox(width: 10),
text.toText(
fontSize: 15,
isBold: true,
color: MyColors.lightTextColor,
),
],
),
),
);
}
}

@ -2,34 +2,94 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class PickedImagesContainer extends StatelessWidget {
final List<File> pickedImages;
final Function(String filePath) onCrossPressed;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
final Function() onAddImagePressed;
const PickedImagesContainer({
Key? key,
required this.pickedImages,
required this.onCrossPressed,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
required this.onAddImagePressed,
this.isReview = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GridView.count(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 4,
crossAxisSpacing: 4.0,
mainAxisSpacing: 8.0,
children: List.generate(
isReview ? pickedImages.length : pickedImages.length + 1,
(index) {
if (index == pickedImages.length && !isReview) {
return Container(
margin: EdgeInsets.all(8),
color: MyColors.lightTextColor.withOpacity(0.4),
alignment: Alignment.center,
child: Container(
height: 24,
width: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: Icon(
Icons.add,
color: MyColors.white,
),
),
).onPress(onAddImagePressed);
}
return Center(
child: BuildImageContainer(
file: pickedImages[index],
onCrossPressedPrimary: onCrossPressedPrimary,
onCrossPressedSecondary: onCrossPressedSecondary,
index: index,
isReview: isReview,
),
);
},
),
);
return Wrap(
children: pickedImages.map((file) => BuildImageContainer(file: file, onCrossPressed: onCrossPressed,)).toList(),
children: pickedImages
.map((file) => BuildImageContainer(
file: file,
onCrossPressedPrimary: onCrossPressedPrimary,
onCrossPressedSecondary: onCrossPressedSecondary,
index: index,
isReview: isReview,
))
.toList(),
);
}
}
class BuildImageContainer extends StatelessWidget {
final File file;
final Function(String filePath) onCrossPressed;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
const BuildImageContainer({
Key? key,
required this.file,
required this.onCrossPressed,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
this.isReview = false,
}) : super(key: key);
@override
@ -37,8 +97,8 @@ class BuildImageContainer extends StatelessWidget {
return Stack(
children: [
Container(
height: 80,
width: 80,
height: 90,
width: 90,
child: Stack(
children: [
Image.file(
@ -47,16 +107,22 @@ class BuildImageContainer extends StatelessWidget {
height: 72,
width: 70,
).paddingAll(8),
Align(
alignment: Alignment.topRight,
child: MyAssets.closeWithOrangeBg.buildSvg(
fit: BoxFit.fill,
height: 25,
width: 25,
),
).onPress(() {
onCrossPressed(file.path);
})
!isReview
? Align(
alignment: Alignment.topRight,
child: MyAssets.closeWithOrangeBg.buildSvg(
fit: BoxFit.fill,
height: 30,
width: 30,
),
).onPress(() {
if (onCrossPressedPrimary == null) {
onCrossPressedSecondary!(index!, file.path);
return;
}
onCrossPressedPrimary!(file.path);
})
: SizedBox()
],
)),
],

@ -1,13 +1,14 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
class FiltersList extends StatelessWidget {
final List<FilterListModel> filterList;
final Function(int) onFilterTapped;
final bool needLeftPadding;
class CategoriesList extends StatelessWidget {
// We will pass a list here!
final String name;
final Function() onTapped;
const CategoriesList({Key? key, required this.name, required this.onTapped}) : super(key: key);
const FiltersList({Key? key, required this.filterList, this.needLeftPadding = true, required this.onFilterTapped}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -15,27 +16,29 @@ class CategoriesList extends StatelessWidget {
height: 37,
width: double.infinity,
child: ListView.builder(
padding: const EdgeInsets.only(left: 12),
itemCount: 20,
padding: EdgeInsets.only(left: needLeftPadding ? 12 : 0),
itemCount: filterList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: onTapped,
onTap: () {
onFilterTapped(index);
},
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 8),
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: index < 1 ? MyColors.darkIconColor : null,
color: filterList[index].isSelected ? MyColors.darkIconColor : null,
border: Border.all(
color: index < 1 ? MyColors.darkIconColor : MyColors.primaryColor,
color: filterList[index].isSelected ? MyColors.darkIconColor : MyColors.primaryColor,
width: 2,
),
),
child: name.toText(
fontSize: 12,
color: index < 1 ? MyColors.white : null,
),
child: filterList[index].title.toText(
fontSize: 12,
color: filterList[index].isSelected ? MyColors.white : null,
),
),
);
}),

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
class BuildTimeSlots extends StatelessWidget {
const BuildTimeSlots({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 37,
width: double.infinity,
child: ListView.builder(
itemCount: 20,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {},
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.only(right: 8),
width: 50,
decoration: BoxDecoration(
color: index < 1 ? MyColors.darkIconColor : null,
border: Border.all(
color: index < 1 ? MyColors.darkIconColor : MyColors.primaryColor,
width: 2,
),
),
child: "09:00".toText(
fontSize: 12,
color: index < 1 ? MyColors.white : null,
),
),
);
}),
);
}
}

@ -1,13 +1,14 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
class ViewAllWidget extends StatelessWidget {
final String title;
final String subTitle;
final Function() onSubtitleTapped;
const ViewAllWidget({Key? key, required this.title, required this.subTitle}) : super(key: key);
const ViewAllWidget({Key? key, required this.title, required this.subTitle, required this.onSubtitleTapped}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -17,11 +18,14 @@ class ViewAllWidget extends StatelessWidget {
child: Row(
children: [
Expanded(child: title.toText(isBold: true, fontSize: 18)),
subTitle.toText(
fontSize: 11,
isBold: true,
color: MyColors.primaryColor,
textDecoration: TextDecoration.underline,
InkWell(
onTap: onSubtitleTapped,
child: subTitle.toText(
fontSize: 11,
isBold: true,
color: MyColors.primaryColor,
textDecoration: TextDecoration.underline,
),
)
],
),

@ -8,8 +8,9 @@ class DropValue {
int id;
String value;
String subValue;
bool? isEnabled;
DropValue(this.id, this.value, this.subValue);
DropValue(this.id, this.value, this.subValue, {this.isEnabled = true});
bool operator ==(o) => o is DropValue && o.value == value && o.id == id;
}
@ -56,8 +57,8 @@ class _DropdownFieldState extends State<DropdownField> {
iconEnabledColor: borderColor,
iconDisabledColor: borderColor,
isExpanded: true,
style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w600),
hint: (widget.hint ?? "").toText(color: borderColor, fontSize: 12),
style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w600, fontSize: 15),
hint: (widget.hint ?? "").toText(color: borderColor, fontSize: 15),
underline: Container(height: 0),
onChanged: (DropValue? newValue) {
setState(() {
@ -69,7 +70,8 @@ class _DropdownFieldState extends State<DropdownField> {
(DropValue value) {
return DropdownMenuItem<DropValue>(
value: value,
child: value.value.toText(fontSize: 12),
enabled: value.isEnabled ?? true,
child: value.value.toText(fontSize: 15, color: value.isEnabled == false ? Colors.black38 : null),
);
},
).toList(),

@ -354,3 +354,105 @@ extension LocaleSetup on MultiProvider {
extension WidgetExtensions on Widget {
Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this);
}
extension FormatDate on String {
/// get month by
/// [month] convert month number in to month name
/// get month by
/// [month] convert month number in to month name in Arabic
static String getMonthArabic(int month) {
switch (month) {
case 1:
return "يناير";
case 2:
return " فبراير";
case 3:
return "مارس";
case 4:
return "أبريل";
case 5:
return "مايو";
case 6:
return "يونيو";
case 7:
return "يوليو";
case 8:
return "أغسطس";
case 9:
return "سبتمبر";
case 10:
return " اكتوبر";
case 11:
return " نوفمبر";
case 12:
return "ديسمبر";
default:
return "";
}
}
static String getMonth(int month) {
switch (month) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
default:
return "";
}
}
String getTimeAgo() {
String date = split("T")[0];
String time = split("T")[1];
var dates = date.split("-");
return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a', "en_US").format(DateFormat('hh:mm:ss', "en_US").parse(time))}";
}
}
extension DateTimeConversions on DateTime {
String getTimeAgo({bool numericDates = true}) {
final date2 = DateTime.now();
final difference = date2.difference(this);
if ((difference.inDays / 7).floor() >= 1) {
return (numericDates) ? '1 week ago' : 'Last week';
} else if (difference.inDays >= 2) {
return '${difference.inDays} days ago';
} else if (difference.inDays >= 1) {
return (numericDates) ? '1 day ago' : 'Yesterday';
} else if (difference.inHours >= 2) {
return '${difference.inHours} hours ago';
} else if (difference.inHours >= 1) {
return (numericDates) ? '1 hour ago' : 'An hour ago';
} else if (difference.inMinutes >= 2) {
return '${difference.inMinutes} minutes ago';
} else if (difference.inMinutes >= 1) {
return (numericDates) ? '1 minute ago' : 'A minute ago';
} else if (difference.inSeconds >= 3) {
return '${difference.inSeconds} seconds ago';
} else {
return 'Just now';
}
}
}

Loading…
Cancel
Save