Added AdUpdateFlow

localization_aamir
Faiz Hashmi 1 year ago
parent 08cb3f4a85
commit 0c5a45f5af

@ -74,10 +74,7 @@ class ApiClientImp implements ApiClient {
if (headers != null && headers.isNotEmpty) {
headers0.addAll(headers);
}
if (!kReleaseMode) {
logger.i(url);
logger.i(jsonEncode(jsonObject.toString()));
}
var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: headers0, retryTimes: retryTimes);
try {
if (!kReleaseMode) {
@ -129,14 +126,16 @@ class ApiClientImp implements ApiClient {
var queryString = Uri(queryParameters: queryParameters).query;
url = '$url?$queryString';
}
Response response;
response = await _post(Uri.parse(url), body: requestBody, headers: headers0).timeout(const Duration(seconds: 100));
if (!kReleaseMode) {
logger.d("------URL------");
logger.i(url);
logger.i(requestBody);
logger.d("------Payload------");
logger.i(jsonDecode(requestBody));
logger.d("------Response------");
logger.i(jsonDecode(response.body));
}
if (response.statusCode >= 200 && response.statusCode < 500) {

@ -104,6 +104,7 @@ class ApiConsts {
static String vehicleAdsDurationGet = "${baseUrlServices}api/Advertisement/AdsDuration_Get";
static String vehicleAdsSpecialServicesGet = "${baseUrlServices}api/Common/SpecialService_Get";
static String vehicleAdsSingleStepCreate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Create";
static String vehicleAdsSingleStepUpdate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Update";
static String vehicleAdsGet = "${baseUrlServices}api/Advertisement/Ads_Get";
static String myAdsReserveGet = "${baseUrlServices}api/Advertisement/AdsReserve_Get";
static String reserveAdsBankDetailsGet = "${baseUrlServices}api/Advertisement/MCBankAccountAd_Get";

@ -5,18 +5,19 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
extension EmailValidator on String {
Widget toText({Color? color,
bool isBold = false,
double? fontSize,
bool isUnderLine = false,
bool isItalic = false,
TextDecoration? textDecoration,
double letterSpacing = -0.4,
TextAlign? textAlign,
FontWeight? fontWeight,
double? height,
Color? decorationColor,
int? maxLines}) =>
Widget toText(
{Color? color,
bool isBold = false,
double? fontSize,
bool isUnderLine = false,
bool isItalic = false,
TextDecoration? textDecoration,
double letterSpacing = -0.4,
TextAlign? textAlign,
FontWeight? fontWeight,
double? height,
Color? decorationColor,
int? maxLines}) =>
AutoSizeText(
this,
textAlign: textAlign,
@ -24,10 +25,8 @@ extension EmailValidator on String {
style: TextStyle(
fontStyle: isItalic ? FontStyle.italic : null,
height: height,
decoration: isUnderLine ? TextDecoration.underline : textDecoration ??
TextDecoration.none,
decorationColor
: decorationColor,
decoration: isUnderLine ? TextDecoration.underline : textDecoration ?? TextDecoration.none,
decorationColor: decorationColor,
fontSize: fontSize ?? 10,
fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.w600,
color: color ?? MyColors.darkTextColor,
@ -36,9 +35,7 @@ extension EmailValidator on String {
);
bool isValidEmail() {
return RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(this);
return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
}
bool isNum() {
@ -146,9 +143,7 @@ extension FormatDate on String {
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))}";
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))}";
}
String toFormattedDateWithoutTime() {
@ -809,5 +804,3 @@ extension SubscriptionTypeEnumToString on SubscriptionTypeEnum {
}
}
}

@ -260,13 +260,15 @@ class Category {
class Condition {
int? id;
int? vehicleBrandID;
String? label;
String? labelN;
Condition({this.id, this.label, this.labelN});
Condition({this.id, this.label, this.labelN, this.vehicleBrandID});
Condition.fromJson(Map<String, dynamic> json) {
id = json['id'];
vehicleBrandID = json['vehicleBrandID'];
label = json['label'];
labelN = json['labelN'];
}

@ -33,7 +33,6 @@ class VehicleDetailsModel {
});
VehicleDetailsModel.fromJson(Map<String, dynamic> json) {
log("jsonJee: $json");
vehicleBrands = List.generate((json['vehiclebrands']['data']).length, (index) => VehicleBrandsModel.fromJson(json['vehiclebrands']['data'][index]));
vehicleCategories = List.generate((json['vehiclecategories']['data']).length, (index) => VehicleCategoryModel.fromJson(json['vehiclecategories']['data'][index]));
vehicleColors = List.generate((json['vehiclecolors']['data']).length, (index) => VehicleColorModel.fromJson(json['vehiclecolors']['data'][index]));
@ -69,7 +68,6 @@ class VehicleTypeModel {
this.isActive,
this.vehicleTypeEnum = VehicleType.car,
this.isSelected,
});
VehicleTypeModel.fromJson(Map<String, dynamic> json) {

@ -1,3 +1,5 @@
import 'dart:io';
class GenericRespModel {
GenericRespModel({
this.data,
@ -219,16 +221,18 @@ class VehiclePosting {
class VehiclePostingImages {
int? id;
File? file;
String? imageName;
String? imageUrl;
String? imageStr;
int? vehiclePostingID;
String? vehiclePosting;
VehiclePostingImages({this.id, this.imageName, this.imageUrl, this.imageStr, this.vehiclePostingID, this.vehiclePosting});
VehiclePostingImages({this.id, this.file, this.imageName, this.imageUrl, this.imageStr, this.vehiclePostingID, this.vehiclePosting});
VehiclePostingImages.fromJson(Map<String, dynamic> json) {
id = json['id'];
file = null;
imageName = json['imageName'];
imageUrl = json['imageUrl'];
imageStr = json['imageStr'];
@ -249,7 +253,7 @@ class VehiclePostingImages {
@override
String toString() {
return 'VehiclePostingImages{id: $id, imageName: $imageName, imageUrl: $imageUrl, imageStr: $imageStr, vehiclePostingID: $vehiclePostingID, vehiclePosting: $vehiclePosting}';
return 'VehiclePostingImages{id: $id, imageName: $imageName, imageUrl: $imageUrl, imageStr: "", vehiclePostingID: $vehiclePostingID, vehiclePosting: $vehiclePosting}';
}
}
@ -282,17 +286,21 @@ class RequestPostingImages {
class VehiclePostingDamageParts {
int? id;
File? file;
String? comment;
String? imageUrl;
String? vehicleImageBase64;
int? vehicleDamagePartID;
int? vehiclePostingID;
bool? isActive;
VehiclePostingDamageParts({this.id, this.comment, this.vehicleImageBase64, this.vehicleDamagePartID, this.vehiclePostingID, this.isActive});
VehiclePostingDamageParts({this.id, this.file, this.comment, this.imageUrl, this.vehicleImageBase64, this.vehicleDamagePartID, this.vehiclePostingID, this.isActive});
VehiclePostingDamageParts.fromJson(Map<String, dynamic> json) {
id = json['id'];
file = null;
comment = json['comment'];
imageUrl = json['imageUrl'];
vehicleImageBase64 = json['vehicleImageBase64'];
vehicleDamagePartID = json['vehicleDamagePartID'];
vehiclePostingID = json['vehiclePostingID'];
@ -303,6 +311,7 @@ class VehiclePostingDamageParts {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['comment'] = comment;
data['imageUrl'] = imageUrl;
data['vehicleImageBase64'] = vehicleImageBase64;
data['vehicleDamagePartID'] = vehicleDamagePartID;
data['vehiclePostingID'] = vehiclePostingID;
@ -310,8 +319,8 @@ class VehiclePostingDamageParts {
return data;
}
// @override
// String toString() {
// return 'VehiclePostingDamageParts{id: $id, comment: $comment, vehicleImageBase64: $vehicleImageBase64, vehicleDamagePartID: $vehicleDamagePartID, vehiclePostingID: $vehiclePostingID, isActive: $isActive}';
// }
@override
String toString() {
return 'VehiclePostingDamageParts{id: $id, comment: $comment, vehicleImageBase64: $vehicleImageBase64, vehicleDamagePartID: $vehicleDamagePartID, vehiclePostingID: $vehiclePostingID, isActive: $isActive}';
}
}

@ -22,7 +22,7 @@ abstract class AdsRepo {
Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceId});
Future<GenericRespModel> createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel});
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew});
Future<List<AdDetailsModel>> getAllAds({required bool isMyAds});
@ -72,15 +72,15 @@ class AdsRepoImp implements AdsRepo {
}
@override
Future<GenericRespModel> createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}) async {
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}) async {
List vehiclePostingImages = [];
adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) {
var imageMap = {
"id": 0,
"id": element.id ?? 0,
"imageName": element.imageName,
"imageUrl": element.imageUrl,
"imageStr": element.imageStr,
"vehiclePostingID": 0,
"vehiclePostingID": element.vehiclePostingID ?? 0,
"vehiclePosting": null,
};
vehiclePostingImages.add(imageMap);
@ -89,18 +89,18 @@ class AdsRepoImp implements AdsRepo {
List vehiclePostingDamageParts = [];
adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) {
var imageMap = {
"id": 0,
"id": element.id ?? 0,
"comment": element.comment,
"vehicleImageBase64": element.vehicleImageBase64,
"vehicleDamagePartID": element.vehicleDamagePartID,
"vehiclePostingID": 0,
"vehiclePostingID": element.vehiclePostingID ?? 0,
"isActive": true
};
vehiclePostingDamageParts.add(imageMap);
});
var postParams = {
"ads": {
"id": 0,
"id": adsCreationPayloadModel.ads!.id ?? 0,
"adsDurationID": adsCreationPayloadModel.ads!.adsDurationID,
"startDate": adsCreationPayloadModel.ads!.startDate,
"countryId": adsCreationPayloadModel.ads!.countryId,
@ -108,7 +108,7 @@ class AdsRepoImp implements AdsRepo {
"isMCHandled": false
},
"vehiclePosting": {
"id": 0,
"id": adsCreationPayloadModel.vehiclePosting!.id ?? 0,
"userID": adsCreationPayloadModel.vehiclePosting!.userID,
"vehicleType": adsCreationPayloadModel.vehiclePosting!.vehicleType,
"vehicleModelID": adsCreationPayloadModel.vehiclePosting!.vehicleModelID,
@ -134,11 +134,10 @@ class AdsRepoImp implements AdsRepo {
}
};
logger.i(jsonEncode(postParams.toString()));
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleAdsSingleStepCreate,
isCreateNew ? ApiConsts.vehicleAdsSingleStepCreate : ApiConsts.vehicleAdsSingleStepUpdate,
postParams,
token: token,
);

@ -31,14 +31,11 @@ class ChatRepoImp implements ChatRepo {
HubConnection hub;
hub = HubConnectionBuilder()
.withUrl(
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()
..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
log(message);
},
))
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {},
))
.build();
return hub;
}
@ -49,7 +46,7 @@ class ChatRepoImp implements ChatRepo {
"id": messageId.toString(),
};
await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
(json) => GenericRespModel.fromJson(json),
ApiConsts.messageIsReadUpdate,
queryParameters,
token: appState.getUser.data!.accessToken,
@ -68,7 +65,7 @@ class ChatRepoImp implements ChatRepo {
"PageIndex": pageIndex.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
(json) => GenericRespModel.fromJson(json),
ApiConsts.getChatMessages,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
@ -76,7 +73,7 @@ class ChatRepoImp implements ChatRepo {
if (genericRespModel.messageStatus == 1 && genericRespModel.data != null) {
List<ChatMessageModel> chatMessages = List.generate(
genericRespModel.data.length,
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
);
return chatMessages;
}

@ -1,6 +1,10 @@
import 'package:intl/intl.dart';
class DateHelper {
static String formatDateT(String dateString) {
return dateString.split('T')[0];
}
static DateTime parseStringToDate(String dateString) {
final formatter = DateFormat('yyyy-MM-dd');
return formatter.parse(dateString);

@ -21,6 +21,7 @@ import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/repositories/ads_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/date_helper.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';
@ -71,7 +72,8 @@ class AdVM extends BaseVM {
String adPhoneNumberError = "";
// Edit Variables Amir
bool isAdEdit = false;
bool isAdEditEnabled = false;
AdDetailsModel? previousAdDetails;
List<AdDetailsModel> exploreAds = [];
List<AdDetailsModel> exploreAdsFilteredList = [];
@ -385,18 +387,22 @@ class AdVM extends BaseVM {
// notifyListeners();
// }
getVehicleBrandsByVehicleTypeId() async {
if (vehicleTypeId.selectedId == -1 || vehicleBrands.isNotEmpty) {
return;
}
vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: vehicleTypeId.selectedId);
Future<void> getVehicleBrandsByVehicleTypeId({int vehicleIdForEditAd = -1}) async {
// if (vehicleTypeId.selectedId == -1 || vehicleBrands.isNotEmpty) {
// return;
// }
isFetchingLists = true;
notifyListeners();
vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: vehicleIdForEditAd != -1 ? vehicleIdForEditAd : vehicleTypeId.selectedId);
isFetchingLists = false;
notifyListeners();
}
Future<void> getVehicleDetailsByVehicleBrandId() async {
if (vehicleBrandId.selectedId == -1 || vehicleTypeId.selectedId == -1) {
return;
}
// if (vehicleBrandId.selectedId == -1 || vehicleTypeId.selectedId == -1) {
// return;
// }
isFetchingLists = true;
notifyListeners();
vehicleDetails = await commonRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId, vehicleBrandId: vehicleBrandId.selectedId);
@ -461,13 +467,13 @@ class AdVM extends BaseVM {
void updateSelectionVehicleTypeId(SelectionModel id) async {
vehicleTypeId = id;
getVehicleBrandsByVehicleTypeId();
await getVehicleBrandsByVehicleTypeId();
notifyListeners();
}
SelectionModel vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleBrandId(SelectionModel id, {bool isForSearch = false}) {
Future<void> updateSelectionVehicleBrandId(SelectionModel id, {bool isForSearch = false}) async {
if (isForSearch) {
VehicleBrandsModel brand = vehicleBrands.firstWhere((element) => element.id == id.selectedId);
DropValue brandValue = DropValue(brand.id ?? 0, brand.vehicleBrandDescription ?? "", "");
@ -478,7 +484,8 @@ class AdVM extends BaseVM {
return;
}
vehicleBrandId = id;
getVehicleDetailsByVehicleBrandId();
logger.i("message: ${vehicleBrandId.selectedOption}");
await getVehicleDetailsByVehicleBrandId();
notifyListeners();
}
@ -881,7 +888,7 @@ class AdVM extends BaseVM {
} else {
vehicleDescError = "";
}
if (pickedVehicleImages.isEmpty || pickedVehicleImages.length < 3) {
if ((pickedPostingImages.isEmpty || pickedPostingImages.length < 3) && !isAdEditEnabled) {
vehicleImageError = GlobalConsts.attachImageError;
isValidated = false;
} else {
@ -1010,8 +1017,14 @@ class AdVM extends BaseVM {
case AdCreationSteps.damageParts:
if (isDamagePartsValidated()) {
currentProgressStep = AdCreationSteps.adDuration;
getVehicleAdsDuration();
getVehicleAdsSpecialServices();
if (vehicleAdsDurations.isEmpty) {
getVehicleAdsDuration();
}
if (vehicleAdsSpecialServices.isEmpty) {
getVehicleAdsSpecialServices();
}
notifyListeners();
}
break;
@ -1029,6 +1042,7 @@ class AdVM extends BaseVM {
Utils.hideLoading(context);
return;
}
isAdEditEnabled = false;
Utils.hideLoading(context);
currentProgressStep = AdCreationSteps.vehicleDetails;
resetValues();
@ -1065,30 +1079,35 @@ class AdVM extends BaseVM {
notifyListeners();
}
List<File> pickedVehicleImages = [];
List<ImageModel> pickedPostingImages = [];
void removeImageFromList(String filePath) {
int index = pickedVehicleImages.indexWhere((element) => element.path == filePath);
int index = pickedPostingImages.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
}
pickedVehicleImages.removeAt(index);
pickedPostingImages.removeAt(index);
notifyListeners();
}
void pickMultipleImages() async {
List<ImageModel> imageModels = [];
List<File> images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(images);
if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
for (var element in images) {
imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false));
}
pickedPostingImages.addAll(imageModels);
if (pickedPostingImages.isNotEmpty) vehicleImageError = "";
notifyListeners();
}
List<File> pickedReceiptPdfFiles = [];
List<ImageModel> pickedReceiptPdfFiles = [];
String receiptPdfFileError = "";
void removePdfFileFromList(String filePath) {
int index = pickedReceiptPdfFiles.indexWhere((element) => element.path == filePath);
int index = pickedReceiptPdfFiles.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
}
@ -1097,8 +1116,13 @@ class AdVM extends BaseVM {
}
void pickPdfReceiptFile(BuildContext context) async {
List<ImageModel> imageModels = [];
List<File>? files = await commonServices.pickMultipleFiles(context);
pickedReceiptPdfFiles.addAll(files!);
if (files == null) return;
for (var element in files) {
imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false));
}
pickedReceiptPdfFiles.addAll(imageModels);
if (pickedReceiptPdfFiles.isNotEmpty) receiptPdfFileError = "";
notifyListeners();
}
@ -1106,13 +1130,16 @@ class AdVM extends BaseVM {
// sourceFlag for Camera = 0
// sourceFlag for Gallery = 1
void pickDamagePartImage(int index) async {
List<ImageModel> imageModels = [];
List<File> images = await commonServices.pickMultipleImages();
for (var element in images) {
imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false));
}
if (images.isNotEmpty) {
if (vehicleDamageCards[index].partImages == null) {
vehicleDamageCards[index].partImages = images;
vehicleDamageCards[index].partImages = imageModels;
} else {
vehicleDamageCards[index].partImages!.addAll(images);
vehicleDamageCards[index].partImages!.addAll(imageModels);
}
vehicleDamageCards[index].partImageErrorValue = "";
notifyListeners();
@ -1147,7 +1174,7 @@ class AdVM extends BaseVM {
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);
int index = card.partImages!.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
}
@ -1164,9 +1191,10 @@ class AdVM extends BaseVM {
void resetValues() {
pickedDamageImages.clear();
pickedVehicleImages.clear();
pickedPostingImages.clear();
vehicleDamageCards.clear();
specialServiceCards.clear();
vehicleAdsSpecialServices.clear();
currentProgressStep = AdCreationSteps.vehicleDetails;
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
@ -1181,14 +1209,13 @@ class AdVM extends BaseVM {
vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleAdDurationId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleDemandAmount = "";
vehicleVin = "";
vehicleTitle = "";
warrantyDuration = "";
vehicleDescription = "";
selectionDurationStartDate = "";
clearSpecialServiceCard();
updateFinanceAvailableStatus(false);
notifyListeners();
}
@ -1327,6 +1354,7 @@ class AdVM extends BaseVM {
adsSelectedServices.add(value.serviceSelectedId!.selectedId);
}
Ads ads = Ads(
id: isAdEditEnabled ? previousAdDetails!.id : null,
adsDurationID: vehicleAdDurationId.selectedId,
startDate: selectionDurationStartDate,
countryId: vehicleCountryId.selectedId,
@ -1334,8 +1362,8 @@ class AdVM extends BaseVM {
);
List<VehiclePostingImages> vehicleImages = [];
for (var element in pickedVehicleImages) {
vehicleImages.add(await convertFileToVehiclePostingImages(file: element));
for (var image in pickedPostingImages) {
vehicleImages.add(await convertFileToVehiclePostingImages(imageModel: image));
}
List<VehiclePostingDamageParts> vehicleDamageImages = [];
@ -1344,7 +1372,7 @@ class AdVM extends BaseVM {
if (card.partImages != null && card.partImages!.isNotEmpty) {
for (var image in card.partImages!) {
VehiclePostingDamageParts stringImage = await convertFileToVehiclePostingDamageParts(
file: image,
imageModel: image,
damagePartId: card.partSelectedId!.selectedId,
);
vehicleDamageImages.add(stringImage);
@ -1353,6 +1381,7 @@ class AdVM extends BaseVM {
}
VehiclePosting vehiclePosting = VehiclePosting(
id: isAdEditEnabled ? previousAdDetails!.vehiclePostingID : null,
userID: appState.getUser.data!.userInfo!.userId,
vehicleType: vehicleTypeId.selectedId,
vehicleModelID: vehicleModelId.selectedId,
@ -1379,32 +1408,57 @@ class AdVM extends BaseVM {
);
AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting);
GenericRespModel respModel = await adsRepo.createNewAd(adsCreationPayloadModel: adsCreationPayloadModel);
GenericRespModel respModel = await adsRepo.createOrUpdateAd(adsCreationPayloadModel: adsCreationPayloadModel, isCreateNew: !isAdEditEnabled);
Utils.showToast(respModel.message.toString());
return Future.value(respModel.messageStatus);
}
Future<VehiclePostingImages> convertFileToVehiclePostingImages({required File file}) async {
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
VehiclePostingImages vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
imageUrl: file.path,
);
Future<VehiclePostingImages> convertFileToVehiclePostingImages({required ImageModel imageModel}) async {
VehiclePostingImages vehiclePostingImages;
if (imageModel.isFromNetwork ?? false) {
vehiclePostingImages = VehiclePostingImages(
id: imageModel.id,
imageUrl: imageModel.filePath,
);
} else {
File file = File(imageModel.filePath!);
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
imageUrl: file.path,
vehiclePostingID: isAdEditEnabled ? previousAdDetails!.vehiclePostingID : null,
);
}
return vehiclePostingImages;
}
Future<VehiclePostingDamageParts> convertFileToVehiclePostingDamageParts({required File file, required int damagePartId}) async {
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
VehiclePostingDamageParts vehiclePostingDamageParts = VehiclePostingDamageParts(
vehicleImageBase64: image,
vehicleDamagePartID: damagePartId,
);
Future<VehiclePostingDamageParts> convertFileToVehiclePostingDamageParts({required ImageModel imageModel, required int damagePartId}) async {
VehiclePostingDamageParts vehiclePostingDamageParts;
if (imageModel.isFromNetwork ?? false) {
vehiclePostingDamageParts = VehiclePostingDamageParts(
id: imageModel.id,
vehicleDamagePartID: damagePartId,
imageUrl: imageModel.filePath,
vehiclePostingID: isAdEditEnabled ? previousAdDetails!.vehiclePostingID : null,
);
} else {
File file = File(imageModel.filePath!);
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
vehiclePostingDamageParts = VehiclePostingDamageParts(
vehicleImageBase64: image,
vehicleDamagePartID: damagePartId,
imageUrl: file.path,
);
}
return vehiclePostingDamageParts;
}
@ -1600,25 +1654,21 @@ class AdVM extends BaseVM {
///// Edit Work Amir
void editUpdateAd(BuildContext context, AdDetailsModel previousDetails) {
isAdEdit = true;
void onEditUpdateAdPressed(BuildContext context, AdDetailsModel previousDetails) {
isAdEditEnabled = true;
previousAdDetails = previousDetails;
autoFillSelectedVehicleType();
navigateWithName(context, AppRoutes.selectAdTypeView, arguments: AppState().currentAppType == AppType.provider ? true : false);
checkVehicleStep1(previousDetails);
checkVehicleStep2(previousDetails);
}
void clearEditValues() {
isAdEdit = false;
if (vehicleTypes.isNotEmpty) vehicleTypes.unselectAll();
if (vehicleAdsDurations.isNotEmpty) vehicleAdsDurations.unselectAll();
}
checkVehicleStep1(AdDetailsModel previousDetails) {
logger.d("Step 1");
autoFillSelectedVehicleType() async {
if (vehicleTypes.isEmpty) {
await getVehicleTypes();
return;
}
if (vehicleTypes.isNotEmpty) {
for (var vehicle in vehicleTypes) {
if (vehicle.id == previousDetails.vehicle?.vehicleType) {
if (vehicle.id == previousAdDetails!.vehicle?.vehicleType) {
vehicle.isSelected = true;
break;
}
@ -1627,55 +1677,137 @@ class AdVM extends BaseVM {
notifyListeners();
}
checkVehicleStep2(AdDetailsModel previousDetails) {
logger.d("Step 2");
autoFillSelectedVehicleAdsDuration() async {
if (vehicleAdsDurations.isEmpty) {
await getVehicleAdsDuration();
}
if (vehicleAdsDurations.isNotEmpty) {
for (var adsDuration in vehicleAdsDurations) {
if (adsDuration.price == previousDetails.adsDurationPrice) {
adsDuration.isSelected = true;
break;
}
int index = vehicleAdsDurations.indexWhere((element) => element.price == previousAdDetails!.adsDurationPrice!);
if (index != -1) {
updateVehicleAdDurationId(
SelectionModel(
selectedId: vehicleAdsDurations[index].id ?? 0,
selectedOption: "${vehicleAdsDurations[index].days} Days",
itemPrice: vehicleAdsDurations[index].price!.toInt().toString(),
),
);
}
}
notifyListeners();
}
checkVehicleStep3(AdDetailsModel previousDetails) {
logger.d("Step 3");
if (vehicleBrands.isNotEmpty) {
for (var vBrands in vehicleBrands) {
if (vBrands.id == previousDetails.vehicle.) {
// BrandsId need to be matched here.
vBrands.isSelected = true;
break;
}
}
List<VehiclePostingDamageParts> vehicleOldDamageImagesList = [];
void removeVehicleOldDamageImagesList(String imageUrl) {
int index = vehicleOldDamageImagesList.indexWhere((element) => element.imageUrl == imageUrl);
if (index == -1) {
return;
}
vehicleOldDamageImagesList.removeAt(index);
notifyListeners();
}
updateValues() {
if (isAdEdit) {
if (vehicleTypes.isNotEmpty) vehicleTypes.unselectAll();
if (vehicleAdsDurations.isNotEmpty) vehicleAdsDurations.unselectAll();
notifyListeners();
autoFillSelectedVehicleAdsDetails() async {
int index = vehicleBrands.indexWhere((element) => element.id == previousAdDetails!.vehicle!.model!.vehicleBrandID);
if (index != -1) {
await updateSelectionVehicleBrandId(SelectionModel(selectedId: vehicleBrands[index].id!, selectedOption: vehicleBrands[index].vehicleBrandDescription ?? ""));
}
updateSelectionVehicleModelId(SelectionModel(selectedId: previousAdDetails!.vehicle!.model!.id!, selectedOption: previousAdDetails!.vehicle!.model!.label ?? ""));
updateSelectionVehicleModelYearId(SelectionModel(selectedId: previousAdDetails!.vehicle!.modelyear!.id!, selectedOption: previousAdDetails!.vehicle!.modelyear!.label ?? ""));
updateSelectionVehicleColorId(SelectionModel(selectedId: previousAdDetails!.vehicle!.color!.id!, selectedOption: previousAdDetails!.vehicle!.color!.label ?? ""));
updateSelectionVehicleConditionId(SelectionModel(selectedId: previousAdDetails!.vehicle!.condition!.id!, selectedOption: previousAdDetails!.vehicle!.condition!.label ?? ""));
updateSelectionVehicleCategoryId(SelectionModel(selectedId: previousAdDetails!.vehicle!.category!.id!, selectedOption: previousAdDetails!.vehicle!.category!.label ?? ""));
updateSelectionVehicleMileageId(SelectionModel(
selectedId: previousAdDetails!.vehicle!.mileage!.id!, selectedOption: "${previousAdDetails!.vehicle!.mileage!.mileageStart} - ${previousAdDetails!.vehicle!.mileage!.mileageEnd}"));
updateSelectionVehicleTransmissionId(SelectionModel(selectedId: previousAdDetails!.vehicle!.transmission!.id!, selectedOption: previousAdDetails!.vehicle!.transmission!.label ?? ""));
updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: previousAdDetails!.vehicle!.sellertype!.id!, selectedOption: previousAdDetails!.vehicle!.sellertype!.label ?? ""));
int indexCountry = vehicleCountries.indexWhere((element) => element.id == previousAdDetails!.vehicle!.countryID);
if (indexCountry != -1) {
updateSelectionVehicleCountryId(SelectionModel(selectedId: vehicleCountries[index].id!, selectedOption: vehicleCountries[index].countryName ?? ""));
}
updateSelectionVehicleCityId(SelectionModel(selectedId: previousAdDetails!.vehicle!.cityID!, selectedOption: previousAdDetails!.vehicle!.cityName ?? ""));
vehicleDemandAmount = previousAdDetails!.vehicle!.demandAmount!.toInt().toString();
vehicleVin = previousAdDetails!.vehicle!.vehicleVIN.toString();
vehicleTitle = previousAdDetails!.vehicle!.vehicleTitle.toString();
vehicleDescription = previousAdDetails!.vehicle!.vehicleDescription.toString();
financeAvailableStatus = previousAdDetails!.vehicle!.isFinanceAvailable ?? false;
if (previousAdDetails!.vehicle!.image != null && previousAdDetails!.vehicle!.image!.isNotEmpty) {
for (var element in previousAdDetails!.vehicle!.image!) {
if (element.imageUrl != null) {
ImageModel imageModel = ImageModel(id: element.id, filePath: element.imageUrl, isFromNetwork: true);
pickedPostingImages.add(imageModel);
}
}
}
}
}
extension ToggleSelected on List {
void unselectAll() {
for (var element in this) {
if (element.isSelected!) {
element.isSelected = false;
if (previousAdDetails!.vehicle!.damagereport != null && previousAdDetails!.vehicle!.damagereport!.isNotEmpty) {
for (var element in previousAdDetails!.vehicle!.damagereport!) {
int index = -1;
if (vehicleDamageCards.isNotEmpty) {
index = ifDamagePartAlreadyThere(element.vehicleDamagePartID!);
ImageModel imageModel = ImageModel(id: element.id!, filePath: element.imageUrl!, isFromNetwork: true);
vehicleDamageCards[index].partImages!.add(imageModel);
} else {
ImageModel imageModel = ImageModel(id: element.id!, filePath: element.imageUrl!, isFromNetwork: true);
VehicleDamageCard vehicleDamageCard = VehicleDamageCard(
partSelectedId: SelectionModel(
selectedId: element.vehicleDamagePartID!,
selectedOption: element.partName ?? "",
),
partImages: [imageModel],
);
addNewDamagePartCard(damageCard: vehicleDamageCard);
}
}
}
if (previousAdDetails!.specialservice != null && previousAdDetails!.specialservice!.isNotEmpty) {
for (var element in previousAdDetails!.specialservice!) {
SelectionModel vehicleAdsSpecialServicesId = SelectionModel(selectedId: element.specialServiceID!, selectedOption: element.name ?? "", itemPrice: element.price.toString());
SpecialServiceCard specialServiceCard = SpecialServiceCard(
serviceSelectedId: vehicleAdsSpecialServicesId,
description: element.description ?? "",
duration: "",
serviceDate: "",
serviceDateError: "",
serviceTimeError: "",
address: "",
serviceTime: "",
);
addNewSpecialServiceCard(specialServiceCard: specialServiceCard);
}
}
selectionDurationStartDate = DateHelper.formatDateT(previousAdDetails!.startdate ?? "");
isPhoneNumberShown = previousAdDetails!.phoneNo != null;
if (isPhoneNumberShown) {
adPhoneNumber = previousAdDetails!.phoneNo ?? "";
adPhoneNumberDialCode = "+966";
}
isNumberOnWhatsApp = previousAdDetails!.whatsAppNo != null;
logger.i("previousAdDetails!: $previousAdDetails");
notifyListeners();
}
int ifDamagePartAlreadyThere(int partId) {
return vehicleDamageCards.indexWhere((element) => element.partSelectedId!.selectedId == partId);
}
int ifSpecialServiceAlreadyThere(int id) {
return specialServiceCards.indexWhere((element) => element.serviceSelectedId!.selectedId == id);
}
}
// Edit Work End Amir
class VehicleDamageCard {
List<File>? partImages;
List<ImageModel>? partImages;
SelectionModel? partSelectedId;
String partImageErrorValue;
@ -1684,6 +1816,24 @@ class VehicleDamageCard {
this.partSelectedId,
this.partImageErrorValue = "",
});
@override
String toString() {
return 'VehicleDamageCard{partImages: $partImages, partSelectedId: $partSelectedId, partImageErrorValue: $partImageErrorValue}';
}
}
class ImageModel {
int? id;
bool? isFromNetwork;
String? filePath;
ImageModel({this.id, this.filePath, this.isFromNetwork});
@override
String toString() {
return 'ImageModel{id: $id, isFromNetwork: $isFromNetwork, filePath: $filePath}';
}
}
class SpecialServiceCard {

@ -21,6 +21,7 @@ import 'package:mc_common_app/services/common_services.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/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:provider/provider.dart';
@ -97,11 +98,11 @@ class RequestsVM extends BaseVM {
notifyListeners();
}
List<File> pickedVehicleImages = [];
List<ImageModel> pickedVehicleImages = [];
String vehicleImageError = "";
void removeImageFromList(String filePath) {
int index = pickedVehicleImages.indexWhere((element) => element.path == filePath);
int index = pickedVehicleImages.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
}
@ -110,8 +111,12 @@ class RequestsVM extends BaseVM {
}
void pickMultipleImages() async {
List<ImageModel> imageModels = [];
List<File> images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(images);
for (var element in images) {
imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false));
}
pickedVehicleImages.addAll(imageModels);
if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
notifyListeners();
}
@ -251,7 +256,7 @@ class RequestsVM extends BaseVM {
log("requestImages: ${pickedVehicleImages.length}");
for (var image in pickedVehicleImages) {
var value = await convertFileToRequestPostingImages(file: image);
var value = await convertFileToRequestPostingImages(file: File(image.filePath!));
requestImages.add(value);
}

@ -110,10 +110,10 @@ class VehicleDetailsReview extends StatelessWidget {
SingleDetailWidget(text: adVM.vehicleDescription, type: "Description"),
8.height,
"Vehicle Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
if (adVM.pickedVehicleImages.isNotEmpty) ...[
if (adVM.pickedPostingImages.isNotEmpty) ...[
// 10.height,
PickedFilesContainer(
pickedFiles: adVM.pickedVehicleImages,
pickedFiles: adVM.pickedPostingImages,
onCrossPressedPrimary: adVM.removeImageFromList,
isReview: true,
onAddFilePressed: () {},

@ -6,6 +6,7 @@ import 'package:mc_common_app/theme/colors.dart';
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/network_images_container.dart';
import 'package:mc_common_app/views/advertisement/picked_images_container.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
@ -128,6 +129,7 @@ class DamageParts extends StatelessWidget {
],
).paddingOnly(right: 10)
],
],
).toWhiteContainer(
width: double.infinity,

@ -7,6 +7,7 @@ import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/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/network_images_container.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';
@ -276,16 +277,27 @@ class VehicleDetails extends StatelessWidget {
],
).paddingOnly(right: 10)
],
if (adVM.pickedVehicleImages.isNotEmpty) ...[
if (adVM.pickedPostingImages.isNotEmpty) ...[
16.height,
PickedFilesContainer(
pickedFiles: adVM.pickedVehicleImages,
pickedFiles: adVM.pickedPostingImages,
onCrossPressedPrimary: adVM.removeImageFromList,
onAddFilePressed: () {
context.read<AdVM>().pickMultipleImages();
},
),
],
// if (adVM.isAdEditEnabled) ...[
// if (adVM.previousAdDetails!.vehicle!.image!.isNotEmpty) ...[
// 16.height,
// "Old Images".toText(fontSize: 16),
// NetworkFilesContainerForVehiclePosting(
// networkFilesForVehiclePosting: adVM.vehicleOldImagesList,
// onCrossPressedPrimary: adVM.removeVehicleOldImagesList,
// onAddFilePressed: () => context.read<AdVM>().pickMultipleImages(),
// ),
// ],
// ],
15.height,
],
]

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -71,13 +72,10 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
),
],
).toWhiteContainer(
width: double.infinity,
allPading: 12,
isBorderRequired: adDuration.isSelected!
? true
: adDuration.id == adVM.vehicleAdDurationId.selectedId
? true
: false),
width: double.infinity,
allPading: 12,
isBorderRequired: adDuration.id == adVM.vehicleAdDurationId.selectedId,
),
).onPress(() {
if (isFromExtendAd) {
adVM.updateVehicleExtendAdDurationId(
@ -96,7 +94,6 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
itemPrice: adDuration.price!.toInt().toString(),
),
);
adVM.updateValues();
});
},
separatorBuilder: (BuildContext context, int index) {
@ -106,15 +103,27 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
),
),
ShowFillButton(
title: "Select",
iconWidget: adVM.isFetchingLists ? const Padding(
padding: EdgeInsets.all(8.0),
child: SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(color: Colors.white),
),
) : null,
title: adVM.isFetchingLists ? "" : "Select",
maxWidth: double.infinity,
margin: const EdgeInsets.all(21),
onPressed: () {
if (isFromExtendAd && !isUpdateAdSelected) {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.extendAds);
if (adVM.isFetchingLists) {
return;
} else {
if (isFromExtendAd && !isUpdateAdSelected) {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.extendAds);
return;
}
navigateReplaceWithName(context, AppRoutes.createAdView);
}
navigateReplaceWithName(context, AppRoutes.createAdView);
},
).toContainer(paddingAll: 0, backgroundColor: Colors.white),
],

@ -21,7 +21,6 @@ import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_duration_selection_sheet_content.dart';
import 'package:mc_common_app/views/advertisement/ads_images_slider.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:mc_common_app/views/appointments/widgets/custom_calender_widget.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart';
@ -33,7 +32,6 @@ 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:sizer/sizer.dart';
class AdsDetailView extends StatefulWidget {
final AdDetailsModel adDetails;
@ -93,14 +91,8 @@ class _AdsDetailViewState extends State<AdsDetailView> {
);
}
void editAd() {
AdVM adVM = context.read<AdVM>();
adVM.editUpdateAd(context, widget.adDetails);
}
@override
Widget build(BuildContext context) {
log("ad: ${widget.adDetails.vehicle!.image!.first.imageUrl}");
return Scaffold(
appBar: CustomAppBar(
title: "Ads",
@ -109,16 +101,16 @@ class _AdsDetailViewState extends State<AdsDetailView> {
isDrawerEnabled: false,
actions: [
((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved)
? IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () {
return deleteAdBottomSheet(context);
},
)
: IconButton(
icon: const Icon(Icons.chat_outlined, color: Colors.black),
onPressed: () {},
))
? IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () {
return deleteAdBottomSheet(context);
},
)
: IconButton(
icon: const Icon(Icons.chat_outlined, color: Colors.black),
onPressed: () {},
))
.toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
@ -149,7 +141,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: "${widget.adDetails.vehicle!.vehicleTitle} | ${widget.adDetails.vehicle!.color!.label} | AdID: ${widget.adDetails.id}".toText(
child: "${widget.adDetails.vehicle!.vehicleTitle} | ${widget.adDetails.vehicle!.color!.label} | ${widget.adDetails.id}".toText(
fontSize: 18,
isBold: true,
maxLines: 2,
@ -278,29 +270,31 @@ class _AdsDetailViewState extends State<AdsDetailView> {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Rejection Comments".toText(fontSize: 18, isBold: true, color: MyColors.lightTextColor),
"Rejection Comments".toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor),
Row(
children: [
Icon(
Icons.edit,
size: 15,
),
"Edit Ad".toText(fontSize: 10, isBold: true),
2.width,
"Edit Add".toText(fontSize: 10, isBold: true),
const Icon(Icons.edit, size: 15),
],
).onPress(() {
logger.i(widget.adDetails);
editAd();
).onPress(() async {
Utils.showLoading(context);
await context.read<AdVM>().getVehicleTypes();
await context.read<AdVM>().getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1);
Utils.hideLoading(context);
context.read<AdVM>().onEditUpdateAdPressed(context, widget.adDetails);
}),
],
).paddingOnly(bottom: 5),
Row(
children: [
(widget.adDetails.comment ?? "").toText(
color: MyColors.redColor,
fontSize: 12,
isItalic: true,
),
Flexible(
child: (widget.adDetails.comment ?? "").toText(
color: MyColors.redColor,
fontSize: 12,
isItalic: true,
),
)
],
),
],
@ -525,36 +519,36 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
Widget defaultActionForProviderAndCustomer(BuildContext context, AdDetailsModel adDetailsModel) {
return (adDetailsModel.phoneNo == null)
? Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Contact",
fontSize: 18,
isBold: false,
iconWidget: const Padding(
padding: EdgeInsets.only(right: 10),
child: Icon(Icons.phone, color: MyColors.white, size: 24),
),
onPressed: () {
Utils.openNumberViaCaller(phoneNumber: adDetailsModel.phoneNo ?? "");
},
),
),
if (adDetailsModel.whatsAppNo == null) ...[
8.width,
Container(
height: 55,
width: 55,
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
child: MyAssets.whatsAppIcon.buildSvg(height: 33, width: 35))
.onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),
],
],
)
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Contact",
fontSize: 18,
isBold: false,
iconWidget: const Padding(
padding: EdgeInsets.only(right: 10),
child: Icon(Icons.phone, color: MyColors.white, size: 24),
),
onPressed: () {
Utils.openNumberViaCaller(phoneNumber: adDetailsModel.phoneNo ?? "");
},
),
),
if (adDetailsModel.whatsAppNo == null) ...[
8.width,
Container(
height: 55,
width: 55,
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
child: MyAssets.whatsAppIcon.buildSvg(height: 33, width: 35))
.onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),
],
],
)
: const SizedBox.shrink();
}
@ -598,23 +592,23 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
adVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: Builder(
builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (int i = 0; i < adVM.photoSSSchedulesByOffices.length; i++) {
var element = adVM.photoSSSchedulesByOffices[i];
vehicleCitiesDrop.add(DropValue(element.photoOfficeID?.toInt() ?? 0, element.photoOfficeName ?? "", i.toString()));
}
builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (int i = 0; i < adVM.photoSSSchedulesByOffices.length; i++) {
var element = adVM.photoSSSchedulesByOffices[i];
vehicleCitiesDrop.add(DropValue(element.photoOfficeID?.toInt() ?? 0, element.photoOfficeName ?? "", i.toString()));
}
return DropdownField(
(DropValue value) => adVM.updatePhotoOfficeSelectedId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
// here the item price is the index of the selected option
list: vehicleCitiesDrop,
dropdownValue: adVM.photoOfficeSelectedId.selectedId != -1 ? DropValue(adVM.photoOfficeSelectedId.selectedId, adVM.photoOfficeSelectedId.selectedOption, "") : null,
hint: "Select Office",
errorValue: adVM.photoOfficeSelectedId.errorValue,
);
},
),
return DropdownField(
(DropValue value) => adVM.updatePhotoOfficeSelectedId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
// here the item price is the index of the selected option
list: vehicleCitiesDrop,
dropdownValue: adVM.photoOfficeSelectedId.selectedId != -1 ? DropValue(adVM.photoOfficeSelectedId.selectedId, adVM.photoOfficeSelectedId.selectedOption, "") : null,
hint: "Select Office",
errorValue: adVM.photoOfficeSelectedId.errorValue,
);
},
),
if (adVM.photoOfficeSelectedId.selectedId != -1) ...[
9.height,
CustomCalenderAppointmentWidget(
@ -959,7 +953,10 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
return InfoBottomSheet(
title: "Cancel Reservation".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: Consumer<AdVM>(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
@ -1075,7 +1072,10 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
return InfoBottomSheet(
title: "Upload Bank Receipt".toText(fontSize: 26, 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: Consumer<AdVM>(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(
@ -1107,27 +1107,28 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
},
isPdf: true,
),
] else ...[
Row(
children: [
Container(
height: 90,
width: 90,
decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)),
margin: const EdgeInsets.all(8),
alignment: Alignment.center,
child: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).onPress(() {
context.read<AdVM>().pickPdfReceiptFile(context);
}),
],
),
],
] else
...[
Row(
children: [
Container(
height: 90,
width: 90,
decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)),
margin: const EdgeInsets.all(8),
alignment: Alignment.center,
child: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).onPress(() {
context.read<AdVM>().pickPdfReceiptFile(context);
}),
],
),
],
15.height,
ShowFillButton(
title: "Submit",
@ -1256,6 +1257,8 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
return pendingForReviewAction(pendingText: "Waiting for Admins Approval");
case AdPostStatus.sold:
return pendingForReviewAction(pendingText: "Sold");
case AdPostStatus.expired:
return expiredAdAction(context);
case AdPostStatus.allAds:

@ -6,7 +6,7 @@ import 'package:mc_common_app/theme/colors.dart';
class CarouselWithIndicatorDemo extends StatefulWidget {
final List<AdImage> vehicleImages;
const CarouselWithIndicatorDemo({key, required this.vehicleImages});
const CarouselWithIndicatorDemo({super.key, required this.vehicleImages});
@override
State<StatefulWidget> createState() => _CarouselWithIndicatorState();
@ -16,21 +16,15 @@ class _CarouselWithIndicatorState extends State<CarouselWithIndicatorDemo> {
int _current = 0;
final CarouselController _controller = CarouselController();
// final imgList = [
// MyAssets.bnCar,
// MyAssets.bnCar,
// MyAssets.bnCar,
// ];
@override
Widget build(BuildContext context) {
return Column(children: [
CarouselSlider(
items: widget.vehicleImages
.map((item) => Container(
margin: EdgeInsets.all(5.0),
margin: const EdgeInsets.all(5.0),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
child: Image.network(
item.imageUrl!,
fit: BoxFit.cover,
@ -64,7 +58,7 @@ class _CarouselWithIndicatorState extends State<CarouselWithIndicatorDemo> {
child: Container(
width: 12.0,
height: 12.0,
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == entry.key ? MyColors.darkPrimaryColor : MyColors.lightTextColor.withOpacity(0.5),

@ -34,7 +34,7 @@ class _CreateAdViewState extends State<CreateAdView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: adVM.isAdEdit ? "Update Ad": "Create Ad",
title: adVM.isAdEditEnabled ? "Update Ad": "Create Ad",
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => adVM.onBackButtonPressed(context),

@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class NetworkFilesContainerForVehiclePosting extends StatelessWidget {
final List<VehiclePostingImages> networkFilesForVehiclePosting;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
final Function() onAddFilePressed;
const NetworkFilesContainerForVehiclePosting({
Key? key,
required this.networkFilesForVehiclePosting,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
required this.onAddFilePressed,
this.isReview = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GridView.count(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 4,
crossAxisSpacing: 4.0,
mainAxisSpacing: 8.0,
children: List.generate(
networkFilesForVehiclePosting.length,
(index) {
return Center(
child: BuildNetworkContainer(
fileUrl: networkFilesForVehiclePosting[index].imageUrl ?? "",
onCrossPressedPrimary: onCrossPressedPrimary,
onCrossPressedSecondary: onCrossPressedSecondary,
index: index,
isReview: isReview,
));
},
),
);
}
}
class NetworkFilesContainerForDamagedParts extends StatelessWidget {
final List<VehiclePostingDamageParts> networkFilesForDamagedParts;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
final Function() onAddFilePressed;
const NetworkFilesContainerForDamagedParts({
Key? key,
required this.networkFilesForDamagedParts,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
required this.onAddFilePressed,
this.isReview = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GridView.count(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 4,
crossAxisSpacing: 4.0,
mainAxisSpacing: 8.0,
children: List.generate(
networkFilesForDamagedParts.length,
(index) {
return Center(
child: BuildNetworkContainer(
fileUrl: networkFilesForDamagedParts[index].imageUrl ?? "",
onCrossPressedPrimary: onCrossPressedPrimary,
onCrossPressedSecondary: onCrossPressedSecondary,
index: index,
isReview: isReview,
));
},
),
);
}
}
class BuildNetworkContainer extends StatelessWidget {
final String fileUrl;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
final bool isPdf;
const BuildNetworkContainer({
Key? key,
required this.fileUrl,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
this.isReview = false,
this.isPdf = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
SizedBox(
height: 90,
width: 90,
child: Stack(
children: [
isPdf
? Container(
height: 72,
width: 70,
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: MyColors.darkPrimaryColor,
)),
child: const Icon(Icons.picture_as_pdf).paddingAll(8),
)
: Image.network(
fileUrl,
fit: BoxFit.fill,
height: 72,
width: 70,
).paddingAll(8),
!isReview
? Align(
alignment: Alignment.topRight,
child: MyAssets.closeWithOrangeBg.buildSvg(
fit: BoxFit.fill,
height: 30,
width: 30,
),
).onPress(() {
if (onCrossPressedPrimary == null) {
onCrossPressedSecondary!(index!, fileUrl);
return;
}
onCrossPressedPrimary!(fileUrl);
})
: const SizedBox()
],
)),
],
);
}
}

@ -3,15 +3,17 @@ 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/view_models/ad_view_model.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class PickedFilesContainer extends StatelessWidget {
final List<File> pickedFiles;
final List<ImageModel> pickedFiles;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
final bool isReview;
final bool isPdf;
final bool isFromNetwork;
final Function() onAddFilePressed;
const PickedFilesContainer({
@ -23,6 +25,7 @@ class PickedFilesContainer extends StatelessWidget {
required this.onAddFilePressed,
this.isReview = false,
this.isPdf = false,
this.isFromNetwork = false,
}) : super(key: key);
@override
@ -51,7 +54,7 @@ class PickedFilesContainer extends StatelessWidget {
}
return Center(
child: BuildFilesContainer(
file: pickedFiles[index],
image: pickedFiles[index],
onCrossPressedPrimary: onCrossPressedPrimary,
onCrossPressedSecondary: onCrossPressedSecondary,
index: index,
@ -76,7 +79,7 @@ class PickedFilesContainer extends StatelessWidget {
}
class BuildFilesContainer extends StatelessWidget {
final File file;
final ImageModel image;
final Function(String filePath)? onCrossPressedPrimary;
final Function(int index, String filePath)? onCrossPressedSecondary;
final int? index;
@ -85,7 +88,7 @@ class BuildFilesContainer extends StatelessWidget {
const BuildFilesContainer({
Key? key,
required this.file,
required this.image,
this.onCrossPressedPrimary,
this.onCrossPressedSecondary,
this.index,
@ -114,12 +117,19 @@ class BuildFilesContainer extends StatelessWidget {
)),
child: const Icon(Icons.picture_as_pdf).paddingAll(8),
)
: Image.file(
file,
fit: BoxFit.fill,
height: 72,
width: 70,
).paddingAll(8),
: image.isFromNetwork!
? Image.network(
image.filePath!,
fit: BoxFit.fill,
height: 72,
width: 70,
).paddingAll(8)
: Image.file(
File(image.filePath!),
fit: BoxFit.fill,
height: 72,
width: 70,
).paddingAll(8),
!isReview
? Align(
alignment: Alignment.topRight,
@ -130,10 +140,10 @@ class BuildFilesContainer extends StatelessWidget {
),
).onPress(() {
if (onCrossPressedPrimary == null) {
onCrossPressedSecondary!(index!, file.path);
onCrossPressedSecondary!(index!, image.filePath!);
return;
}
onCrossPressedPrimary!(file.path);
onCrossPressedPrimary!(image.filePath!);
})
: const SizedBox()
],

@ -59,134 +59,129 @@ class SelectAdTypeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
logger.d("Clead All Values");
// clearAll(context);
AdVM adVM = context.read<AdVM>();
adVM.clearEditValues();
return true;
},
child: Scaffold(
appBar: CustomAppBar(
title: "Select Ad Type",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
),
body: Column(
children: [
Expanded(
child: Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return ListView.separated(
itemCount: adVM.vehicleTypes.length,
itemBuilder: (BuildContext context, int index) {
VehicleTypeModel vehicleTypeModel = adVM.vehicleTypes[index];
return InkWell(
onTap: () {
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: vehicleTypeModel.id!, selectedOption: vehicleTypeModel.vehicleTypeName ?? "", errorValue: ""),
);
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isUpdateAdSelected: false, isFromExtendAd: false));
},
child: SizedBox(
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
return Scaffold(
appBar: CustomAppBar(
title: "Select Ad Type",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
),
body: Column(
children: [
Expanded(
child: Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return ListView.separated(
itemCount: adVM.vehicleTypes.length,
itemBuilder: (BuildContext context, int index) {
VehicleTypeModel vehicleTypeModel = adVM.vehicleTypes[index];
return InkWell(
onTap: () {
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: vehicleTypeModel.id!, selectedOption: vehicleTypeModel.vehicleTypeName ?? "", errorValue: ""),
);
if (adVM.isAdEditEnabled) {
adVM.autoFillSelectedVehicleAdsDuration();
adVM.autoFillSelectedVehicleAdsDetails();
}
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isUpdateAdSelected: false, isFromExtendAd: false));
},
child: SizedBox(
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
vehicleTypeModel.vehicleTypeName.toString().toText(fontSize: 18, isBold: true),
getVehicleAdTypeIcon(vehicleTypeModel.vehicleTypeEnum!),
],
),
if (isProvider) ...[
Row(
children: [
"Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"Valid Until Subscription Expiration".toText(fontSize: 13, isBold: true),
],
).paddingOnly(top: 5, bottom: 5),
] else ...[
Row(
children: [
"Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
adVM.vehicleAdDurationId.selectedOption.toText(fontSize: 13, isBold: true),
const Icon(Icons.keyboard_arrow_down_sharp, color: MyColors.darkPrimaryColor, size: 20),
],
).paddingOnly(top: 5, bottom: 5),
],
if (!isProvider) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
vehicleTypeModel.vehicleTypeName.toString().toText(fontSize: 18, isBold: true),
getVehicleAdTypeIcon(vehicleTypeModel.vehicleTypeEnum!),
adVM.vehicleAdDurationId.itemPrice.toText(fontSize: 22, isBold: true),
2.width,
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: "SAR".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
),
],
),
if (isProvider) ...[
Row(
children: [
"Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"Valid Until Subscription Expiration".toText(fontSize: 13, isBold: true),
],
).paddingOnly(top: 5, bottom: 5),
] else ...[
Row(
children: [
"Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
adVM.vehicleAdDurationId.selectedOption.toText(fontSize: 13, isBold: true),
const Icon(Icons.keyboard_arrow_down_sharp, color: MyColors.darkPrimaryColor, size: 20),
],
).paddingOnly(top: 5, bottom: 5),
],
if (!isProvider) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
adVM.vehicleAdDurationId.itemPrice.toText(fontSize: 22, isBold: true),
2.width,
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: "SAR".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
),
],
),
],
],
),
],
),
],
),
),
],
),
).toWhiteContainer(width: double.infinity, isBorderRequired: vehicleTypeModel.isSelected! ? true : false, pading: const EdgeInsets.symmetric(horizontal: 20, vertical: 10)),
);
},
separatorBuilder: (BuildContext context, int index) {
return 9.height;
},
padding: const EdgeInsets.all(20),
);
}),
),
if (isProvider) ...[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
);
},
separatorBuilder: (BuildContext context, int index) {
return 9.height;
},
padding: const EdgeInsets.all(20),
);
}),
),
if (isProvider) ...[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
"5 of 10 ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1),
"Ads Remaining ".toText(fontSize: 17, color: MyColors.lightTextColor, isBold: true),
],
),
const Text.rich(
TextSpan(
children: [
"5 of 10 ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1),
"Ads Remaining ".toText(fontSize: 17, color: MyColors.lightTextColor, isBold: true),
TextSpan(
text: "You have left with 05 out of 50 ads given in the subscription. ",
style: TextStyle(
fontSize: 14,
color: MyColors.lightTextColor,
)),
TextSpan(
text: "Update Subscription",
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 14,
fontWeight: FontWeight.w600,
color: MyColors.darkPrimaryColor,
))
],
),
const Text.rich(
TextSpan(
children: [
TextSpan(
text: "You have left with 05 out of 50 ads given in the subscription. ",
style: TextStyle(
fontSize: 14,
color: MyColors.lightTextColor,
)),
TextSpan(
text: "Update Subscription",
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 14,
fontWeight: FontWeight.w600,
color: MyColors.darkPrimaryColor,
))
],
),
),
10.height,
],
).toContainer(paddingAll: 20, backgroundColor: Colors.white),
]
],
),
),
10.height,
],
).toContainer(paddingAll: 20, backgroundColor: Colors.white),
]
],
),
);
}

Loading…
Cancel
Save