@ -1,5 +1,4 @@
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 ' ;
@ -10,7 +9,9 @@ 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/utils.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 ' ;
@ -22,13 +23,48 @@ 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 State less Widget {
class ChatView extends State fu lWidget {
final ChatViewArguments chatViewArguments ;
const ChatView ( { super . key , required this . chatViewArguments } ) ;
@ override
State < ChatView > createState ( ) = > _ChatViewState ( ) ;
}
class _ChatViewState extends State < ChatView > {
late ChatVM chatVM ;
late ChatTypeEnum chatTypeEnum ;
ChatViewArgumentsForRequest ? chatViewArgumentsForRequest ;
ChatViewArgumentsForAd ? chatViewArgumentsForAd ;
@ override
void initState ( ) {
chatTypeEnum = widget . chatViewArguments . chatTypeEnum ;
if ( chatTypeEnum = = ChatTypeEnum . ads ) {
chatViewArgumentsForAd = widget . chatViewArguments . chatViewArgumentsForAd ;
} else if ( chatTypeEnum = = ChatTypeEnum . requestOffer ) {
chatViewArgumentsForRequest = widget . chatViewArguments . chatViewArgumentsForRequest ;
}
chatVM = context . read < ChatVM > ( ) ;
chatVM . isUserOnChatScreen = true ;
WidgetsBinding . instance . addPostFrameCallback ( ( _ ) {
if ( chatVM . scrollController . hasClients ) {
chatVM . scrollChatDown ( ) ;
}
} ) ;
super . initState ( ) ;
}
@ override
void dispose ( ) {
chatVM . isUserOnChatScreen = false ;
super . dispose ( ) ;
}
Future buildSendOfferBottomSheet ( BuildContext context ) {
RequestModel requestDetail = chatViewArguments . requestModel ! ;
RequestModel requestDetail = chatViewArguments ForRequest! . requestModel ! ;
return showModalBottomSheet (
context: context ,
isScrollControlled: true ,
@ -51,6 +87,7 @@ class ChatView extends StatelessWidget {
errorValue: requestsVM . offerPriceError ,
keyboardType: TextInputType . number ,
hint: LocaleKeys . enterAmount . tr ( ) ,
numbersOnly: true ,
onChanged: ( v ) = > requestsVM . updateOfferPrice ( v ) ,
) ,
12. height ,
@ -75,7 +112,7 @@ class ChatView extends StatelessWidget {
requestId: requestDetail . id ,
offerPrice: requestsVM . offerPrice ,
requestModel: requestDetail ,
requestIndex: chatViewArguments . requestIndex ,
requestIndex: chatViewArguments ForRequest! . requestIndex ,
isFromChatScreen: true ,
) ;
} ,
@ -90,20 +127,44 @@ class ChatView extends StatelessWidget {
) ;
}
Future < bool > onTextMessageSend ( ) async {
bool status = false ;
if ( chatTypeEnum = = ChatTypeEnum . requestOffer ) {
status = await chatVM . onTextMessageSendForRequest (
context: context ,
receiverId: chatViewArgumentsForRequest ! . receiverId ,
message: chatVM . chatMessageText ,
requestId: chatViewArgumentsForRequest ! . requestId ? ? 0 ,
offerPrice: " 0.0 " ,
chatMessageType: ChatMessageTypeEnum . freeText ,
) ;
} else if ( chatTypeEnum = = ChatTypeEnum . ads ) {
} else { }
return status ;
}
@ 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 (
List < ChatMessageModel > chatMessages = [ ] ;
if ( chatTypeEnum = = ChatTypeEnum . ads ) {
chatMessages = chatViewArgumentsForAd ! . adDetailsModel ! . adMessages ? ? [ ] ;
} else if ( chatTypeEnum = = ChatTypeEnum . requestOffer ) {
if ( AppState ( ) . currentAppType = = AppType . customer ) {
chatMessages = chatVM . serviceProviderOffersList [ chatViewArgumentsForRequest ! . providerIndex ] . chatMessages ? ? [ ] ;
} else {
chatMessages = requestVM . myFilteredRequests [ chatViewArgumentsForRequest ! . requestIndex ] . chatMessages ;
}
}
return Column (
children: [
Expanded (
child: chatMessages . isEmpty
? Center ( child: LocaleKeys . noRequestsShow . tr ( ) . toText ( fontSize: 16 , color: MyColors . lightTextColor ) )
: ListView . separated (
controller: chatVM . scrollController ,
itemCount: chatMessages . length ,
separatorBuilder: ( BuildContext context , int index ) = > 20. height ,
itemBuilder: ( BuildContext context , int index ) {
@ -111,73 +172,73 @@ class ChatView extends StatelessWidget {
return ChatMessageCustomWidget ( chatMessageModel: chatMessageModel ) ;
} ,
) . horPaddingMain ( ) ,
) ,
10. height ,
Row (
crossAxisAlignment: CrossAxisAlignment . center ,
children: [
if ( requestVM . currentSelectedRequest ! . requestStatus = = RequestStatus . inProgress ) . . . [
Center (
child: LocaleKeys . requestAlreadyInProgress . tr ( ) . toText (
textAlign: TextAlign . center ,
color: MyColors . lightTextColor ,
fontSize: 14 ,
) ,
) . paddingAll ( 15 )
] else . . . [
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 ) ,
) ,
) ,
10. height ,
Row (
crossAxisAlignment: CrossAxisAlignment . center ,
children: [
if ( chatTypeEnum = = ChatTypeEnum . requestOffer & & requestVM . currentSelectedRequest ! . requestStatus = = RequestStatus . inProgress ) . . . [
Center (
child: LocaleKeys . requestAlreadyInProgress . tr ( ) . toText (
textAlign: TextAlign . center ,
color: MyColors . lightTextColor ,
fontSize: 14 ,
) ,
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 ,
) ;
) . paddingAll ( 15 )
] else . . . [
if ( AppState ( ) . currentAppType = = AppType . provider & & chatTypeEnum = = ChatTypeEnum . requestOffer ) . . . [
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 {
final status = await chatVM . onTextMessageSendForRequest (
context: context ,
receiverId: chatViewArgumentsForRequest ! . receiverId ,
message: chatVM . chatMessageText ,
requestId: chatViewArgumentsForRequest ! . requestId ? ? 0 ,
offerPrice: " 0.0 " ,
chatMessageType: ChatMessageTypeEnum . freeText ,
) ;
if ( status ) {
chatVM . clearChatMessageText ( ) ;
}
} ,
) ,
) ,
] ,
] ,
) . toContainer ( isShadowEnabled: true ) ,
if ( status ) {
chatVM . scrollChatDown ( ) ;
chatVM . clearChatMessageText ( ) ;
}
} ,
) ,
) ,
] ,
) ;
] ,
) . toContainer ( isShadowEnabled: true ) ,
] ,
) ;
} ) ,
/ / body:
) ;
@ -194,7 +255,7 @@ class ChatMessageCustomWidget extends StatefulWidget {
}
class _ChatMessageCustomWidgetState extends State < ChatMessageCustomWidget > {
Future buildRejectOfferBottomSheet ( ) {
Future buildRejectOfferBottomSheet ( {required ChatMessageModel chatMessageModel } ) {
return showModalBottomSheet (
context: context ,
isScrollControlled: true ,
@ -228,21 +289,55 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
) ;
} ,
) ,
12. height ,
TxtField (
maxLines: 5 ,
value: chatVM . rejectOfferDescription ,
errorValue: chatVM . rejectOfferDescriptionError ,
keyboardType: TextInputType . text ,
hint: LocaleKeys . description . tr ( ) ,
onChanged: ( v ) = > chatVM . updateRejectOfferDescription ( v ) ,
) ,
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: ( ) { } ,
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 . receiverUserID ? ? " " ,
chatMessageType: ChatMessageTypeEnum . offer ,
comments: comments ,
requestId: chatMessageModel . reqOffer ! . requestID ? ? - 1 ,
serviceProviderID: chatMessageModel . serviceProviderID ? ? 0 ,
requestOfferID: chatMessageModel . reqOffer ! . id ? ? - 1 ,
offerPrice: chatMessageModel . reqOffer ! . price . toString ( ) ,
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 ,
@ -254,6 +349,65 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
) ;
}
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 {
log ( " ServiceProviderID: ${ chatMessageModel . toString ( ) } " ) ;
Navigator . pop ( context ) ;
/ / int status = await context . read < ChatVM > ( ) . onActionOfferTapped (
/ / context: context ,
/ / requestOfferStatusEnum: RequestOfferStatusEnum . accepted ,
/ / reqOfferId: chatMessageModel . reqOfferID ? ? - 1 ,
/ / comments: GlobalConsts . acceptingThisOffer ,
/ / ) ;
bool status = await context . read < ChatVM > ( ) . onSendMessageForActionOnRequestOffer (
receiverId: chatMessageModel . receiverUserID ? ? " " ,
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 ( ) ,
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 ;
@ -281,19 +435,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
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 ) {
if ( chatMessageModel . reqOfferID = = status ) {
chatMessageModel . reqOffer ! . requestOfferStatusEnum = RequestOfferStatusEnum . accepted ;
setState ( ( ) { } ) ;
}
}
onPressed: ( ) {
offerAcceptConfirmationBottomSheet ( chatMessageModel: chatMessageModel ) ;
} ,
backgroundColor: MyColors . white ,
txtColor: MyColors . greenColor ,
@ -310,7 +453,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
txtColor: MyColors . redColor ,
fontSize: 9 ,
onPressed: ( ) async {
buildRejectOfferBottomSheet ( ) ;
buildRejectOfferBottomSheet ( chatMessageModel: chatMessageModel ) ;
} ,
) ,
)