Service Request Done
parent
e7fa2bfac8
commit
c3696586f3
@ -0,0 +1,371 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
|
||||
import 'package:mc_common_app/models/general_models/widgets_models.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:mc_common_app/view_models/ad_view_model.dart';
|
||||
import 'package:mc_common_app/view_models/payment_view_model.dart';
|
||||
import 'package:mc_common_app/views/advertisement/ads_detail_view/components.dart';
|
||||
import 'package:mc_common_app/views/advertisement/bottom_sheets/ads_damage_part_pictures_sheet.dart';
|
||||
import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart';
|
||||
import 'package:mc_common_app/widgets/bottom_sheet.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';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class AdsDetailView extends StatefulWidget {
|
||||
final AdDetailsModel adDetails;
|
||||
|
||||
const AdsDetailView({Key? key, required this.adDetails}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AdsDetailView> createState() => _AdsDetailViewState();
|
||||
}
|
||||
|
||||
class _AdsDetailViewState extends State<AdsDetailView> {
|
||||
late AdVM adVM;
|
||||
late List<VehicleDamageCard> damagePartsPictures;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
adVM = context.read<AdVM>();
|
||||
damagePartsPictures = [];
|
||||
scheduleMicrotask(() {
|
||||
onAdDetailsLoaded();
|
||||
populateDamagePartPictures();
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Future<void> onAdDetailsLoaded() async {
|
||||
context.read<PaymentVM>().updateCurrentAdId(id: widget.adDetails.id!);
|
||||
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus == AdPostStatus.reserved)) {
|
||||
await adVM.getAdBankingAccountInfo(adId: widget.adDetails.id!);
|
||||
}
|
||||
}
|
||||
|
||||
void populateDamagePartPictures() {
|
||||
if (widget.adDetails.vehicle!.damagereport != null && widget.adDetails.vehicle!.damagereport!.isNotEmpty) {
|
||||
for (var element in widget.adDetails.vehicle!.damagereport!) {
|
||||
int index = -1;
|
||||
ImageModel imageModel = ImageModel(id: element.id!, filePath: element.imageUrl!, isFromNetwork: true);
|
||||
|
||||
VehicleDamageCard vehicleDamageCard = VehicleDamageCard(
|
||||
partSelectedId: SelectionModel(
|
||||
selectedId: element.vehicleDamagePartID!,
|
||||
selectedOption: element.partName ?? "",
|
||||
),
|
||||
partImages: [imageModel],
|
||||
);
|
||||
damagePartsPictures.add(vehicleDamageCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deleteAdBottomSheet(BuildContext context) {
|
||||
return actionConfirmationBottomSheet(
|
||||
context: context,
|
||||
title: LocaleKeys.deleteAdConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
||||
subtitle: LocaleKeys.deleteAdConfirmationMessage.tr(),
|
||||
actionButtonYes: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: LocaleKeys.yes.tr(),
|
||||
fontSize: 15,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
adVM.deleteMyAd(context, adId: widget.adDetails.id!);
|
||||
},
|
||||
),
|
||||
),
|
||||
actionButtonNo: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
isFilled: false,
|
||||
borderColor: MyColors.darkPrimaryColor,
|
||||
title: LocaleKeys.no.tr(),
|
||||
txtColor: MyColors.darkPrimaryColor,
|
||||
fontSize: 15,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildVehicleDetailsWidget() {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ImagesCorouselWidget(imagesList: widget.adDetails.vehicle!.image!),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: "${widget.adDetails.vehicle!.vehicleTitle} | ${widget.adDetails.vehicle!.color!.label} | ${widget.adDetails.id}".toText(
|
||||
fontSize: 18,
|
||||
isBold: true,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
(widget.adDetails.vehicle!.cityName ?? "").toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
("${LocaleKeys.model.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
"${widget.adDetails.vehicle!.modelyear!.label}".toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
"${widget.adDetails.vehicle!.countryID}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
("${LocaleKeys.mileage.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
"${widget.adDetails.vehicle!.mileage!.mileageEnd}Km".toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
widget.adDetails.createdOn != null ? DateTime.parse(widget.adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) : const SizedBox(),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
("${LocaleKeys.transmission.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
"${widget.adDetails.vehicle!.transmission!.label}".toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
8.height,
|
||||
("${LocaleKeys.description.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
"${widget.adDetails.vehicle!.vehicleDescription}".toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
if (widget.adDetails.isMyAd ?? false) ...[
|
||||
8.height,
|
||||
("${LocaleKeys.demand.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
widget.adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, height: 1.2, isBold: true),
|
||||
LocaleKeys.sar.tr().toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
|
||||
],
|
||||
),
|
||||
if (widget.adDetails.adPostStatus == AdPostStatus.expired) ...[
|
||||
8.height,
|
||||
const Divider(thickness: 1, height: 1),
|
||||
8.height,
|
||||
LocaleKeys.adDurationExpired.tr().toText(
|
||||
color: MyColors.redColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
],
|
||||
]
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||
}
|
||||
|
||||
Widget buildBankDetailsIfAvailable() {
|
||||
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
|
||||
if (adVM.adsBankDetailsModel != null) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LocaleKeys.bankDetails.tr().toText(fontSize: 18, isBold: true),
|
||||
// Row(
|
||||
// children: [
|
||||
// "Full Name: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
// "${widget.adDetails.vehicle!.vehicleDescription}".toText(
|
||||
// fontSize: 14,
|
||||
// isBold: true,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
Row(
|
||||
children: [
|
||||
("${LocaleKeys.bankName.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
(adVM.adsBankDetailsModel!.bankName ?? "").toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
("${LocaleKeys.iban.tr()}: ").toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
|
||||
(adVM.adsBankDetailsModel!.iban ?? "").toText(
|
||||
fontSize: 14,
|
||||
isBold: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildAdRejectionDetails() {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
LocaleKeys.rejectionComments.tr().toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor),
|
||||
Row(
|
||||
children: [
|
||||
LocaleKeys.editAd.tr().toText(fontSize: 10, isBold: true),
|
||||
2.width,
|
||||
const Icon(Icons.edit, size: 15),
|
||||
],
|
||||
).onPress(() async {
|
||||
Utils.showLoading(context);
|
||||
await adVM.getVehicleTypes();
|
||||
await adVM.getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1);
|
||||
Utils.hideLoading(context);
|
||||
adVM.onEditUpdateAdPressed(context: context, previousDetails: widget.adDetails, isFromExtendAd: false);
|
||||
}),
|
||||
],
|
||||
).paddingOnly(bottom: 5),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: (widget.adDetails.comment ?? "").toText(
|
||||
color: MyColors.redColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||
}
|
||||
|
||||
Widget buildDamagePartDetails() {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyAssets.carHitIcon.buildSvg(color: MyColors.darkTextColor),
|
||||
10.width,
|
||||
LocaleKeys.damagePartPictures.tr().toText(fontSize: 16),
|
||||
],
|
||||
),
|
||||
const Icon(Icons.arrow_forward_ios_rounded, size: 20)
|
||||
],
|
||||
).paddingOnly(top: 5, bottom: 5).onPress(() {
|
||||
showMyBottomSheet(context, child: AdDamagePartPicturesSheet(adDamageReportList: widget.adDetails.vehicle!.damagereport ?? []));
|
||||
}).toWhiteContainer(width: double.infinity, allPading: 12);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: LocaleKeys.vehicleDetails.tr(),
|
||||
profileImageUrl: MyAssets.bnCar,
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
actions: [
|
||||
((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active)
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
|
||||
onPressed: () {
|
||||
return deleteAdBottomSheet(context);
|
||||
},
|
||||
)
|
||||
: IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails)))
|
||||
.toContainer(
|
||||
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
|
||||
paddingAll: 0,
|
||||
padding: const EdgeInsets.only(right: 21),
|
||||
borderRadius: 100,
|
||||
borderColor: MyColors.lightGreyEFColor,
|
||||
isEnabledBorder: true,
|
||||
height: 40,
|
||||
width: 42,
|
||||
)
|
||||
],
|
||||
onTap: () {},
|
||||
),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
buildVehicleDetailsWidget(),
|
||||
12.height,
|
||||
buildBankDetailsIfAvailable(),
|
||||
if (widget.adDetails.vehicle!.damagereport != null && widget.adDetails.vehicle!.damagereport!.isNotEmpty) ...[
|
||||
buildDamagePartDetails(),
|
||||
],
|
||||
12.height,
|
||||
if (widget.adDetails.adPostStatus == AdPostStatus.rejected) ...[
|
||||
buildAdRejectionDetails(),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
if (!(widget.adDetails.isMyAd ?? false)) ...[
|
||||
const Divider(thickness: 1, height: 1),
|
||||
18.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
widget.adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, isBold: true),
|
||||
LocaleKeys.sar.tr().toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
|
||||
],
|
||||
),
|
||||
14.height,
|
||||
],
|
||||
widget.adDetails.isMyAd ?? false ? BuildAdDetailsActionButtonForMyAds(adDetailsModel: widget.adDetails) : BuildAdDetailsActionButtonForExploreAds(adDetailsModel: widget.adDetails),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,389 @@
|
||||
import 'dart:developer';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:mc_common_app/view_models/chat_view_model.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:mc_common_app/widgets/txt_field.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:easy_localization/easy_localization.dart' as lcl;
|
||||
|
||||
class ChatMessageCustomWidget extends StatefulWidget {
|
||||
final ChatMessageModel chatMessageModel;
|
||||
|
||||
const ChatMessageCustomWidget({super.key, required this.chatMessageModel});
|
||||
|
||||
@override
|
||||
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
|
||||
}
|
||||
|
||||
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
||||
Future buildRejectOfferBottomSheet({required ChatMessageModel chatMessageModel}) {
|
||||
return showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
builder: (BuildContext context) {
|
||||
return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
|
||||
return InfoBottomSheet(
|
||||
title: LocaleKeys.makeAnOffer.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
||||
description: Padding(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
12.height,
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: chatVM.offerRejectModelList.length,
|
||||
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 0.5),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
OfferRequestCommentModel offerRequestCommentModel = chatVM.offerRejectModelList[index];
|
||||
return CircleCheckBoxWithTitle(
|
||||
isChecked: offerRequestCommentModel.isSelected ?? false,
|
||||
title: '${offerRequestCommentModel.title}',
|
||||
onSelected: () {
|
||||
chatVM.updateSelectionInOfferRejectModelList(index);
|
||||
},
|
||||
selectedColor: MyColors.darkPrimaryColor,
|
||||
);
|
||||
},
|
||||
),
|
||||
if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) ...[
|
||||
// comparing if the "other" is selected
|
||||
12.height,
|
||||
TxtField(
|
||||
maxLines: 5,
|
||||
value: chatVM.rejectOfferDescription,
|
||||
errorValue: chatVM.rejectOfferDescriptionError,
|
||||
keyboardType: TextInputType.text,
|
||||
hint: LocaleKeys.description.tr(),
|
||||
onChanged: (v) => chatVM.updateRejectOfferDescription(v),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
25.height,
|
||||
ShowFillButton(
|
||||
title: LocaleKeys.submit.tr(),
|
||||
onPressed: () async {
|
||||
String comments = "";
|
||||
if (chatVM.selectedOfferRequestCommentModel.index == chatVM.offerRejectModelList.length - 1) //Other
|
||||
{
|
||||
comments = chatVM.rejectOfferDescription;
|
||||
} else {
|
||||
comments = chatVM.selectedOfferRequestCommentModel.title ?? "";
|
||||
}
|
||||
if (!chatVM.isRejectOfferButtonValidated()) {
|
||||
return;
|
||||
}
|
||||
Navigator.pop(context);
|
||||
bool status = await context.read<ChatVM>().onSendMessageForActionOnRequestOffer(
|
||||
receiverId: chatMessageModel.senderUserID ?? "",
|
||||
chatMessageType: ChatMessageTypeEnum.offer,
|
||||
comments: comments,
|
||||
requestId: chatMessageModel.reqOffer!.requestID ?? -1,
|
||||
serviceProviderID: chatMessageModel.serviceProviderID ?? 0,
|
||||
requestOfferID: chatMessageModel.reqOffer!.id ?? -1,
|
||||
offerPrice: chatMessageModel.reqOffer!.price.toString(),
|
||||
serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "",
|
||||
manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "",
|
||||
manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0,
|
||||
requestOfferStatusEnum: RequestOfferStatusEnum.rejected,
|
||||
context: context,
|
||||
);
|
||||
|
||||
if (status) {
|
||||
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.rejected;
|
||||
setState(() {});
|
||||
// Navigator.pop(context);
|
||||
Utils.showToast("Offer Rejected");
|
||||
// navigateReplaceWithName(context, AppRoutes.dashboard);
|
||||
}
|
||||
},
|
||||
maxWidth: double.infinity,
|
||||
),
|
||||
19.height,
|
||||
],
|
||||
),
|
||||
));
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void offerAcceptConfirmationBottomSheet({required ChatMessageModel chatMessageModel}) {
|
||||
return actionConfirmationBottomSheet(
|
||||
context: context,
|
||||
title: LocaleKeys.acceptOfferConfirmation.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
||||
subtitle: LocaleKeys.acceptOfferConfirmationMessage.tr(),
|
||||
actionButtonYes: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: LocaleKeys.yes.tr(),
|
||||
fontSize: 15,
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
bool status = await context.read<ChatVM>().onSendMessageForActionOnRequestOffer(
|
||||
receiverId: chatMessageModel.senderUserID ?? "",
|
||||
chatMessageType: ChatMessageTypeEnum.offer,
|
||||
comments: GlobalConsts.acceptingThisOffer,
|
||||
requestId: chatMessageModel.reqOffer!.requestID ?? -1,
|
||||
serviceProviderID: chatMessageModel.serviceProviderID ?? 0,
|
||||
requestOfferID: chatMessageModel.reqOffer!.id ?? -1,
|
||||
offerPrice: chatMessageModel.reqOffer!.price.toString(),
|
||||
serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "",
|
||||
manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "",
|
||||
manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0,
|
||||
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
|
||||
context: context,
|
||||
);
|
||||
|
||||
if (status) {
|
||||
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
|
||||
setState(() {});
|
||||
// Navigator.pop(context);
|
||||
Utils.showToast("Offer Accepted");
|
||||
|
||||
// navigateReplaceWithName(context, AppRoutes.dashboard);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
actionButtonNo: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
isFilled: false,
|
||||
borderColor: MyColors.darkPrimaryColor,
|
||||
title: LocaleKeys.no.tr(),
|
||||
txtColor: MyColors.darkPrimaryColor,
|
||||
fontSize: 15,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) {
|
||||
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
|
||||
|
||||
switch (requestOfferStatusEnum) {
|
||||
case RequestOfferStatusEnum.offer:
|
||||
return Column(
|
||||
children: [
|
||||
5.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
"${(chatMessageModel.reqOffer!.price ?? 0.0).toInt()}".toText(fontSize: 19, isBold: true, color: AppState().currentAppType == AppType.provider ? MyColors.white : MyColors.darkTextColor),
|
||||
5.width,
|
||||
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
|
||||
],
|
||||
),
|
||||
if (widget.chatMessageModel.isMyMessage == false) ...[
|
||||
10.height,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 27,
|
||||
title: LocaleKeys.accept.tr(),
|
||||
fontSize: 9,
|
||||
borderColor: MyColors.greenColor,
|
||||
isFilled: false,
|
||||
onPressed: () {
|
||||
offerAcceptConfirmationBottomSheet(chatMessageModel: chatMessageModel);
|
||||
},
|
||||
backgroundColor: MyColors.white,
|
||||
txtColor: MyColors.greenColor,
|
||||
),
|
||||
),
|
||||
20.width,
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 27,
|
||||
title: LocaleKeys.reject.tr(),
|
||||
borderColor: MyColors.redColor,
|
||||
isFilled: false,
|
||||
backgroundColor: MyColors.white,
|
||||
txtColor: MyColors.redColor,
|
||||
fontSize: 9,
|
||||
onPressed: () async {
|
||||
buildRejectOfferBottomSheet(chatMessageModel: chatMessageModel);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
case RequestOfferStatusEnum.negotiate:
|
||||
return Column(
|
||||
children: [
|
||||
Center(
|
||||
child: LocaleKeys.newOfferRequired.tr().toText(
|
||||
color: MyColors.adPendingStatusColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
|
||||
],
|
||||
);
|
||||
case RequestOfferStatusEnum.accepted:
|
||||
return Column(
|
||||
children: [
|
||||
Center(
|
||||
child: LocaleKeys.offerHasBeenAccepted.tr().toText(
|
||||
color: MyColors.adPendingStatusColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
|
||||
],
|
||||
);
|
||||
case RequestOfferStatusEnum.rejected:
|
||||
return Column(
|
||||
children: [
|
||||
Center(
|
||||
child: LocaleKeys.offerHasBeenRejected.tr().toText(
|
||||
color: MyColors.adPendingStatusColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
|
||||
],
|
||||
);
|
||||
case RequestOfferStatusEnum.cancel:
|
||||
return Column(
|
||||
children: [
|
||||
Center(
|
||||
child: LocaleKeys.offerHasBeenCancelled.tr().toText(
|
||||
color: MyColors.adPendingStatusColor,
|
||||
fontSize: 12,
|
||||
isItalic: true,
|
||||
),
|
||||
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget getProfilePicture({String profileImageUrl = ""}) {
|
||||
Widget widget = const SizedBox();
|
||||
|
||||
if (profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userLocalImage != null) {
|
||||
widget = Image.file(
|
||||
AppState().getUser.data!.userInfo!.userLocalImage!,
|
||||
width: 34,
|
||||
height: 34,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
} else if (profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userImageUrl != null) {
|
||||
widget = CachedNetworkImage(
|
||||
imageUrl: AppState().getUser.data!.userInfo!.userImageUrl,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
|
||||
errorWidget: (context, url, error) => const Icon(Icons.supervised_user_circle_outlined),
|
||||
fadeInCurve: Curves.easeIn,
|
||||
width: 34,
|
||||
height: 34,
|
||||
fit: BoxFit.fill,
|
||||
fadeInDuration: const Duration(milliseconds: 1000),
|
||||
useOldImageOnUrlChange: false);
|
||||
}
|
||||
|
||||
return widget.toCircle(borderRadius: 100);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: (widget.chatMessageModel.isMyMessage ?? false) ? TextDirection.rtl : TextDirection.ltr,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: (widget.chatMessageModel.isMyMessage ?? false)
|
||||
? getProfilePicture()
|
||||
: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
alignment: Alignment.center,
|
||||
color: MyColors.darkTextColor,
|
||||
child: ((widget.chatMessageModel.senderName ?? "").getInitials()).toText(color: MyColors.white, isBold: true, fontSize: 12),
|
||||
).toCircle(borderRadius: 100),
|
||||
),
|
||||
10.width,
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
((widget.chatMessageModel.isMyMessage ?? false) ? "You" : widget.chatMessageModel.senderName ?? "").toText(fontSize: 16, isBold: true),
|
||||
],
|
||||
),
|
||||
5.height,
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: (widget.chatMessageModel.chatText ?? "").toText(
|
||||
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
|
||||
fontSize: 12,
|
||||
// isBold: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.chatMessageModel.chatMessageTypeEnum == ChatMessageTypeEnum.offer) ...[
|
||||
buildOfferDetailsInChatMessage(chatMessageModel: widget.chatMessageModel, context: context),
|
||||
],
|
||||
],
|
||||
).toContainer(
|
||||
isShadowEnabled: !(widget.chatMessageModel.isMyMessage ?? false),
|
||||
backgroundColor: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.darkIconColor : MyColors.white,
|
||||
borderRadius: 0,
|
||||
margin: EdgeInsets.fromLTRB((widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0, !(widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,222 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/config/routes.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/utils/navigator.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:mc_common_app/view_models/chat_view_model.dart';
|
||||
import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart';
|
||||
import 'package:mc_common_app/views/requests/request_bottomsheets.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';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class RequestDetailPage extends StatelessWidget {
|
||||
final RequestDetailPageArguments requestDetailPageArguments;
|
||||
|
||||
const RequestDetailPage({Key? key, required this.requestDetailPageArguments}) : super(key: key);
|
||||
|
||||
Widget buildBottomButton({required RequestStatus requestStatus, required String statusText, required BuildContext context, required Function() onViewChatTapped}) {
|
||||
switch (requestStatus) {
|
||||
case RequestStatus.submitted:
|
||||
case RequestStatus.inProgress:
|
||||
case RequestStatus.paid:
|
||||
case RequestStatus.shipping:
|
||||
return ShowFillButton(
|
||||
maxWidth: double.infinity,
|
||||
margin: const EdgeInsets.all(15),
|
||||
maxHeight: 55,
|
||||
title: LocaleKeys.viewChat.tr(),
|
||||
isBold: false,
|
||||
onPressed: onViewChatTapped,
|
||||
);
|
||||
case RequestStatus.completed:
|
||||
case RequestStatus.cancelled:
|
||||
case RequestStatus.expired:
|
||||
case RequestStatus.pending:
|
||||
return buildDisabledButton(statusText);
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildDisabledButton(String text) {
|
||||
return ShowFillButton(
|
||||
backgroundColor: MyColors.grey98Color.withOpacity(0.3),
|
||||
txtColor: MyColors.lightTextColor,
|
||||
maxWidth: double.infinity,
|
||||
margin: const EdgeInsets.all(15),
|
||||
maxHeight: 55,
|
||||
title: text,
|
||||
isBold: false,
|
||||
onPressed: () {},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onViewChatTapped(BuildContext context) async {
|
||||
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
|
||||
chatTypeEnum: ChatTypeEnum.requestOffer,
|
||||
receiverId: requestDetailPageArguments.requestModel.customerID,
|
||||
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
|
||||
requestId: requestDetailPageArguments.requestModel.id,
|
||||
providerIndex: -1,
|
||||
// This will be only sent in case of customer
|
||||
requestModel: requestDetailPageArguments.requestModel,
|
||||
requestIndex: requestDetailPageArguments.requestIndex, // This will be only sent in case of provider
|
||||
);
|
||||
ChatViewArguments chatViewArguments = ChatViewArguments(
|
||||
chatTypeEnum: ChatTypeEnum.requestOffer,
|
||||
chatViewArgumentsForRequest: chatViewArgumentsForRequest,
|
||||
);
|
||||
final chatVM = context.read<ChatVM>();
|
||||
await chatVM
|
||||
.getUsersChatMessagesForProvider(
|
||||
customerId: requestDetailPageArguments.requestModel.customerId,
|
||||
context: context,
|
||||
requestOfferId: 0,
|
||||
requestId: requestDetailPageArguments.requestModel.id,
|
||||
customerRequestIndex: requestDetailPageArguments.requestIndex,
|
||||
)
|
||||
.whenComplete(() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: LocaleKeys.requestDetail.tr(),
|
||||
),
|
||||
body: SizedBox(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
ImagesCorouselWidget(imagesList: requestDetailPageArguments.requestModel.requestImages ?? []),
|
||||
24.height,
|
||||
buildRequestContainer(context),
|
||||
],
|
||||
).toWhiteContainer(
|
||||
width: double.infinity,
|
||||
allPading: 12,
|
||||
margin: const EdgeInsets.only(top: 21, right: 21, left: 21),
|
||||
),
|
||||
if (!requestDetailPageArguments.requestModel.isChatted) ...[
|
||||
ShowFillButton(
|
||||
maxWidth: double.infinity,
|
||||
margin: const EdgeInsets.all(15),
|
||||
maxHeight: 55,
|
||||
title: LocaleKeys.sendOffer.tr(),
|
||||
isBold: false,
|
||||
fontSize: 18,
|
||||
onPressed: () => buildSendOfferBottomSheet(context, requestDetailPageArguments),
|
||||
),
|
||||
] else ...[
|
||||
buildBottomButton(
|
||||
requestStatus: requestDetailPageArguments.requestModel.requestStatus,
|
||||
statusText: "Offer ${requestDetailPageArguments.requestModel.requestStatusName}",
|
||||
context: context,
|
||||
onViewChatTapped: () async => onViewChatTapped(context),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRequestContainer(BuildContext context) {
|
||||
final requestDetail = requestDetailPageArguments.requestModel;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
requestDetail.vehicleTypeName.toText(fontSize: 16, isBold: true),
|
||||
showItem("Manufacturer:", requestDetail.brand),
|
||||
showItem("Model:", "${requestDetail.year}"),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
"${requestDetail.city ?? ""} ${requestDetail.countryName}".toText(
|
||||
color: MyColors.lightTextColor,
|
||||
),
|
||||
if (requestDetail.createdOn != null) ...[
|
||||
DateTime.parse(requestDetail.createdOn!).getTimeAgo().toText(color: MyColors.lightTextColor),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
showItem("Customer Name: ", requestDetail.customerName),
|
||||
showItem("Description: ", requestDetail.description),
|
||||
showItem("Price Range:", ""),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
"${requestDetail.price.toInt()}".toText(fontSize: 25, isBold: true),
|
||||
2.width,
|
||||
LocaleKeys.sar.tr().toText(
|
||||
color: MyColors.lightTextColor,
|
||||
fontSize: 16,
|
||||
height: 2.3,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Utils.statusContainerChip(
|
||||
text: (requestDetail.requestStatusName),
|
||||
chipColor: MyColors.grey98Color.withOpacity(0.3),
|
||||
textColor: MyColors.lightTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// const Icon(Icons.arrow_forward)
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget showItem(String title, String value) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (title.isNotEmpty)
|
||||
title.toText(
|
||||
color: MyColors.lightTextColor,
|
||||
),
|
||||
if (title.isNotEmpty) 2.width,
|
||||
if (value.isNotEmpty) Expanded(child: value.toText(isBold: true)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue