You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
car_common_app/lib/views/chat/chat_view.dart

504 lines
20 KiB
Dart

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/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/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';
import 'package:easy_localization/easy_localization.dart' as lcl;
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: 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,
TxtField(
value: requestsVM.offerPrice,
errorValue: requestsVM.offerPriceError,
keyboardType: TextInputType.number,
hint: LocaleKeys.enterAmount.tr(),
onChanged: (v) => requestsVM.updateOfferPrice(v),
),
12.height,
TxtField(
maxLines: 5,
value: requestsVM.offerDescription,
errorValue: requestsVM.offerDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.description.tr(),
onChanged: (v) =>
requestsVM.updateOfferDescription(v),
),
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
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: CustomAppBar(title: LocaleKeys.chat.tr()),
body: Consumer2<ChatVM, RequestsVM>(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: LocaleKeys.noRequestsShow
.tr()
.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: LocaleKeys.typeMessageHere.tr(),
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<ChatMessageCustomWidget> createState() =>
_ChatMessageCustomWidgetState();
}
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
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: 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,
);
},
),
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: () {},
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,
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: () async {
int status =
await context.read<ChatVM>().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: LocaleKeys.reject.tr(),
borderColor: MyColors.redColor,
isFilled: false,
backgroundColor: MyColors.white,
txtColor: MyColors.redColor,
fontSize: 9,
onPressed: () async {
buildRejectOfferBottomSheet();
},
),
)
],
),
],
],
);
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)),
],
);
}
}
@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),
),
],
),
)
],
),
);
}
}