|
|
|
|
@ -9,13 +9,16 @@ 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/models/requests_models/request_model.dart';
|
|
|
|
|
import 'package:mc_common_app/theme/colors.dart';
|
|
|
|
|
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
|
|
|
|
|
import 'package:mc_common_app/utils/enums.dart';
|
|
|
|
|
import 'package:mc_common_app/utils/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/chat_view_model.dart';
|
|
|
|
|
import 'package:mc_common_app/view_models/requests_view_model.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/checkbox_with_title_desc.dart';
|
|
|
|
|
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
|
|
|
|
|
@ -29,14 +32,130 @@ class ChatMessageCustomWidget extends StatefulWidget {
|
|
|
|
|
final RequestStatusEnum? requestStatusEnum;
|
|
|
|
|
final ChatTypeEnum chatTypeEnum;
|
|
|
|
|
final RequestsTypeEnum requestsTypeEnum;
|
|
|
|
|
final RequestModel requestModel;
|
|
|
|
|
|
|
|
|
|
const ChatMessageCustomWidget({super.key, required this.chatMessageModel, required this.requestStatusEnum, required this.chatTypeEnum, this.requestsTypeEnum = RequestsTypeEnum.specialCarRequest});
|
|
|
|
|
const ChatMessageCustomWidget({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.chatMessageModel,
|
|
|
|
|
required this.requestStatusEnum,
|
|
|
|
|
required this.chatTypeEnum,
|
|
|
|
|
required this.requestModel,
|
|
|
|
|
this.requestsTypeEnum = RequestsTypeEnum.specialCarRequest,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
Future buildDealBottomSheetForSpecialCar({required ChatMessageModel chatMessageModel, required RequestOfferStatusEnum requestOfferStatusEnum}) {
|
|
|
|
|
return showModalBottomSheet(
|
|
|
|
|
context: context,
|
|
|
|
|
isScrollControlled: true,
|
|
|
|
|
enableDrag: true,
|
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
|
return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
|
|
|
|
|
return InfoBottomSheet(
|
|
|
|
|
title: LocaleKeys.pleaseSpecify.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(
|
|
|
|
|
children: [
|
|
|
|
|
CheckBoxWithTitleDescription(
|
|
|
|
|
isSelected: chatVM.dealOptionsModelList[0].isSelected!,
|
|
|
|
|
title: '${chatVM.dealOptionsModelList[0].title}',
|
|
|
|
|
description: '',
|
|
|
|
|
onSelection: (bool value) {
|
|
|
|
|
chatVM.updateIsSelectedInDealOptionsModelList(0, value);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
CheckBoxWithTitleDescription(
|
|
|
|
|
isSelected: chatVM.dealOptionsModelList[1].isSelected ?? false,
|
|
|
|
|
title: '${chatVM.dealOptionsModelList[1].title}',
|
|
|
|
|
description: '',
|
|
|
|
|
onSelection: (bool value) {
|
|
|
|
|
chatVM.updateIsSelectedInDealOptionsModelList(1, value);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
if (chatVM.dealOptionsModelList[1].isSelected!) ...[
|
|
|
|
|
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 chatVM.onSendMessageForActionOnRequestOffer(
|
|
|
|
|
receiverId: (chatMessageModel.isMyMessage ?? false) ? chatMessageModel.receiverUserID ?? "" : 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,
|
|
|
|
|
context: context,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
|
final requestVM = context.read<RequestsVM>();
|
|
|
|
|
chatMessageModel.reqOffer!.requestOfferStatusEnum = requestOfferStatusEnum;
|
|
|
|
|
int index = chatVM.serviceProviderOffersList
|
|
|
|
|
.indexWhere((element) => (element.providerId == requestVM.currentSelectedOffer!.providerId) && (element.requestId == requestVM.currentSelectedOffer!.requestId));
|
|
|
|
|
|
|
|
|
|
if (index != -1) {
|
|
|
|
|
chatVM.serviceProviderOffersList[index].requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum;
|
|
|
|
|
}
|
|
|
|
|
setState(() {});
|
|
|
|
|
// Navigator.pop(context);
|
|
|
|
|
chatVM.updateRejectOfferDescription('');
|
|
|
|
|
Utils.showToast("Offer ${requestOfferStatusEnum == RequestOfferStatusEnum.rejected ? "Rejected" : "Cancelled"}");
|
|
|
|
|
// navigateReplaceWithName(context, AppRoutes.dashboard);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
maxWidth: double.infinity,
|
|
|
|
|
),
|
|
|
|
|
19.height,
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future buildRejectOrCancelOfferBottomSheet({required ChatMessageModel chatMessageModel, required RequestOfferStatusEnum requestOfferStatusEnum}) {
|
|
|
|
|
return showModalBottomSheet(
|
|
|
|
|
context: context,
|
|
|
|
|
@ -149,7 +268,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
if (status) {
|
|
|
|
|
final requestVM = context.read<RequestsVM>();
|
|
|
|
|
chatMessageModel.reqOffer!.requestOfferStatusEnum = requestOfferStatusEnum;
|
|
|
|
|
int index = chatVM.serviceProviderOffersList.indexWhere((element) => (element.providerId == requestVM.currentSelectedOffer!.providerId) && (element.requestId == requestVM.currentSelectedOffer!.requestId));
|
|
|
|
|
int index = chatVM.serviceProviderOffersList
|
|
|
|
|
.indexWhere((element) => (element.providerId == requestVM.currentSelectedOffer!.providerId) && (element.requestId == requestVM.currentSelectedOffer!.requestId));
|
|
|
|
|
|
|
|
|
|
if (index != -1) {
|
|
|
|
|
chatVM.serviceProviderOffersList[index].requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum;
|
|
|
|
|
@ -207,7 +327,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
requestVM.currentSelectedRequest!.requestStatus = RequestStatusEnum.inProgress;
|
|
|
|
|
requestVM.updateAcceptedReqOffer(chatMessageModel.reqOffer!);
|
|
|
|
|
requestVM.updateAcceptedRequestOfferProviderName(chatMessageModel.senderName ?? "");
|
|
|
|
|
int index = chatVM.serviceProviderOffersList.indexWhere((element) => (element.providerId == requestVM.currentSelectedOffer!.providerId) && (element.requestId == requestVM.currentSelectedOffer!.requestId));
|
|
|
|
|
int index = chatVM.serviceProviderOffersList
|
|
|
|
|
.indexWhere((element) => (element.providerId == requestVM.currentSelectedOffer!.providerId) && (element.requestId == requestVM.currentSelectedOffer!.requestId));
|
|
|
|
|
|
|
|
|
|
if (index != -1) {
|
|
|
|
|
chatVM.serviceProviderOffersList[index].requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum;
|
|
|
|
|
@ -281,7 +402,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
isItalic: true,
|
|
|
|
|
),
|
|
|
|
|
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: chatMessageModel.isMyMessage! ? MyColors.adPendingStatusColor.withOpacity(0.16) : MyColors.grey98Color.withOpacity(0.1)),
|
|
|
|
|
).toContainer(
|
|
|
|
|
borderRadius: 40, width: double.infinity, backgroundColor: chatMessageModel.isMyMessage! ? MyColors.adPendingStatusColor.withOpacity(0.16) : MyColors.grey98Color.withOpacity(0.1)),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
@ -294,7 +416,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
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),
|
|
|
|
|
"${(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),
|
|
|
|
|
],
|
|
|
|
|
@ -468,11 +591,37 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
return widget.toCircle(borderRadius: 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onOfferEditIconPressed() async {
|
|
|
|
|
int index = context.read<RequestsVM>().myFilteredRequests.indexWhere((request) => request.id == widget.requestModel.id);
|
|
|
|
|
RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments(
|
|
|
|
|
requestIndex: index, // Not getting used in case of update offer
|
|
|
|
|
requestModel: widget.requestModel,
|
|
|
|
|
);
|
|
|
|
|
RequestsVM requestVM = context.read<RequestsVM>();
|
|
|
|
|
requestVM.resetSendOfferBottomSheet();
|
|
|
|
|
ReqOffer offer = widget.chatMessageModel.reqOffer!;
|
|
|
|
|
requestVM.updateOfferPrice((offer.price ?? "").toString());
|
|
|
|
|
requestVM.updateServiceItem((offer.serviceItemName ?? "").toString());
|
|
|
|
|
requestVM.updateItemManufacturer((offer.manufacturedById ?? "").toString());
|
|
|
|
|
requestVM.updateServiceItemCreatedOn((offer.manufacturedOn ?? "").toString());
|
|
|
|
|
requestVM.updateOfferDescription((widget.chatMessageModel.chatText ?? "").toString());
|
|
|
|
|
requestVM.updateIsDeliveryAvailableStatus((offer.isDeliveryAvailable ?? false));
|
|
|
|
|
if (offer.reqOfferImages != null && offer.reqOfferImages!.isNotEmpty) {
|
|
|
|
|
for (var element in offer.reqOfferImages!) {
|
|
|
|
|
if (element.imageUrl != null) {
|
|
|
|
|
ImageModel imageModel = ImageModel(id: element.id, filePath: element.imageUrl, isFromNetwork: true);
|
|
|
|
|
requestVM.addImageToPickedVehicleImages(imageModel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildSendOfferBottomSheet(context: context, requestDetailPageArguments: requestDetailArguments, isFromChatScreen: true, offerId: offer.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget buildFreeTextDetailsInMessage({required ChatMessageTypeEnum chatMessageTypeEnum}) {
|
|
|
|
|
return Row(
|
|
|
|
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
if (chatMessageTypeEnum == ChatMessageTypeEnum.offer && (widget.chatMessageModel.isMyMessage == true) && widget.chatMessageModel.isRead == true) ...[
|
|
|
|
|
if (chatMessageTypeEnum == ChatMessageTypeEnum.offer && (widget.chatMessageModel.isMyMessage == true) && (widget.chatMessageModel.isRead ?? false)) ...[
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
const Icon(Icons.remove_red_eye_outlined, size: 12, color: MyColors.lightTextColor),
|
|
|
|
|
@ -480,6 +629,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
LocaleKeys.viewed.tr().toText(fontSize: 10, color: MyColors.lightTextColor, fontWeight: MyFonts.Medium),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
] else if (AppState().currentAppType == AppType.provider && chatMessageTypeEnum == ChatMessageTypeEnum.offer && (widget.chatMessageModel.isMyMessage == true)) ...[
|
|
|
|
|
MyAssets.icEdit.buildSvg(color: MyColors.white, height: 15).onPress(() => onOfferEditIconPressed()),
|
|
|
|
|
],
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Directionality(
|
|
|
|
|
@ -487,7 +638,6 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
child: (widget.chatMessageModel.chatText ?? "").toText(
|
|
|
|
|
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
// isBold: true,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
@ -518,12 +668,12 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return SizedBox(
|
|
|
|
|
// height: (gridItemSize * 2) + (spacing * 2), // Fixed height for 2 rows including spacing
|
|
|
|
|
// height: (gridItemSize * 2) + (spacing * 2), // Fixed height for 2 rows including spacing
|
|
|
|
|
child: GridView.builder(
|
|
|
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
|
|
|
// Prevent scrolling inside grid
|
|
|
|
|
// Prevent scrolling inside grid
|
|
|
|
|
shrinkWrap: true,
|
|
|
|
|
// Shrink size to fit the content
|
|
|
|
|
// Shrink size to fit the content
|
|
|
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
|
|
|
crossAxisCount: 2, // Show 2 images per row
|
|
|
|
|
crossAxisSpacing: spacing,
|
|
|
|
|
|