import 'dart:developer'; 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/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/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/enums.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/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/app_bar.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'; class ChatView extends StatelessWidget { final ChatViewArguments chatViewArguments; const ChatView({super.key, required this.chatViewArguments}); Future buildSendOfferBottomSheet(BuildContext context) { RequestModel requestDetail = chatViewArguments.requestModel!; return showModalBottomSheet( context: context, isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { return Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) { return InfoBottomSheet( title: "Make an offer".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, TxtField( value: requestsVM.offerPrice, errorValue: requestsVM.offerPriceError, keyboardType: TextInputType.number, hint: "Enter amount", onChanged: (v) => requestsVM.updateOfferPrice(v), ), 12.height, TxtField( maxLines: 5, value: requestsVM.offerDescription, errorValue: requestsVM.offerDescriptionError, keyboardType: TextInputType.text, hint: "Description", onChanged: (v) => requestsVM.updateOfferDescription(v), ), ], ), 25.height, ShowFillButton( title: "Submit", onPressed: () { requestsVM.onSendOfferPressed( context: context, receiverId: requestDetail.customerID, message: requestsVM.offerDescription, requestId: requestDetail.id, offerPrice: requestsVM.offerPrice, requestModel: requestDetail, requestIndex: chatViewArguments.requestIndex, isFromChatScreen: true, ); }, maxWidth: double.infinity, ), 19.height, ], ), )); }); }, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: const CustomAppBar(title: "Chat"), body: Consumer2(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) { final chatMessages = AppState().currentAppType == AppType.customer ? chatVM.serviceProviderOffersList[chatViewArguments.providerIndex].chatMessages : requestVM.myFilteredRequests[chatViewArguments.requestIndex].chatMessages; return chatMessages == null ? Center(child: "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor)) : Column( children: [ Expanded( child: ListView.separated( itemCount: chatMessages.length, separatorBuilder: (BuildContext context, int index) => 20.height, itemBuilder: (BuildContext context, int index) { ChatMessageModel chatMessageModel = chatMessages[index]; return ChatMessageCustomWidget(chatMessageModel: chatMessageModel); }, ).horPaddingMain(), ), 10.height, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ if (AppState().currentAppType == AppType.provider) ...[ Expanded( flex: 1, child: const Icon( Icons.local_offer_rounded, color: MyColors.darkPrimaryColor, size: 30, ).onPress( () async { buildSendOfferBottomSheet(context); }, ), ), ], Expanded( flex: 8, child: TxtField( value: chatVM.chatMessageText, hint: "Type your message here..", keyboardType: TextInputType.text, isNeedBorder: false, onChanged: (v) => chatVM.updateChatMessageText(v), ), ), Expanded( flex: 1, child: const Icon( Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30, ).onPress( () async { log("chatViewArguments.requestId:${chatViewArguments.requestId}"); final status = await chatVM.onTextMessageSend( context: context, receiverId: chatViewArguments.receiverId, message: chatVM.chatMessageText, requestId: chatViewArguments.requestId ?? 0, offerPrice: "0.0", chatMessageType: ChatMessageTypeEnum.freeText, ); if (status) { chatVM.clearChatMessageText(); } }, ), ) ], ).toContainer(isShadowEnabled: true), ], ); }), // body: ); } } class ChatMessageCustomWidget extends StatefulWidget { final ChatMessageModel chatMessageModel; const ChatMessageCustomWidget({super.key, required this.chatMessageModel}); @override State createState() => _ChatMessageCustomWidgetState(); } class _ChatMessageCustomWidgetState extends State { Future buildRejectOfferBottomSheet() { return showModalBottomSheet( context: context, isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) { return InfoBottomSheet( title: "Make an offer".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, ); }, ), 12.height, TxtField( maxLines: 5, value: chatVM.rejectOfferDescription, errorValue: chatVM.rejectOfferDescriptionError, keyboardType: TextInputType.text, hint: "Description", onChanged: (v) => chatVM.updateRejectOfferDescription(v), ), ], ), 25.height, ShowFillButton( title: "Submit", onPressed: () {}, maxWidth: double.infinity, ), 19.height, ], ), )); }); }, ); } 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}".toText(fontSize: 19, isBold: true, color: AppState().currentAppType == AppType.provider ? MyColors.white : MyColors.darkTextColor), 5.width, "SAR".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: "Accept", fontSize: 9, borderColor: MyColors.greenColor, isFilled: false, onPressed: () async { int status = await context.read().onActionOfferTapped( context: context, requestOfferStatusEnum: RequestOfferStatusEnum.accepted, reqOfferId: chatMessageModel.reqOfferID ?? -1, ); if (status != -1) { log("accepted: $status"); if (chatMessageModel.reqOfferID == status) { chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted; setState(() {}); } } }, backgroundColor: MyColors.white, txtColor: MyColors.greenColor, ), ), 20.width, Expanded( child: ShowFillButton( maxHeight: 27, title: "Reject", borderColor: MyColors.redColor, isFilled: false, backgroundColor: MyColors.white, txtColor: MyColors.redColor, fontSize: 9, onPressed: () async { buildRejectOfferBottomSheet(); }, ), ) ], ), ], ], ); case RequestOfferStatusEnum.negotiate: return Column( children: [ Center( child: "New Offer Required.".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: "Offer has been accepted.".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: "Offer has been rejected.".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: "Offer has been cancelled.".toText( color: MyColors.adPendingStatusColor, fontSize: 12, isItalic: true, ), ).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)), ], ); } } @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: Image.asset( MyAssets.bnCar, width: 34, height: 34, fit: BoxFit.fill, ).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), ), ], ), ) ], ), ); } }