// ignore_for_file: use_build_context_synchronously
import ' dart:convert ' ;
import ' dart:developer ' ;
import ' dart:io ' ;
import ' package:flutter/cupertino.dart ' ;
import ' package:mc_common_app/classes/app_state.dart ' ;
import ' package:mc_common_app/classes/consts.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/main.dart ' ;
import ' package:mc_common_app/models/chat_models/chat_message_model.dart ' ;
import ' package:mc_common_app/models/general_models/generic_resp_model.dart ' ;
import ' package:mc_common_app/models/requests_models/provider_offers_model.dart ' ;
import ' package:mc_common_app/repositories/chat_repo.dart ' ;
import ' package:mc_common_app/repositories/request_repo.dart ' ;
import ' package:mc_common_app/services/common_services.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/requests_view_model.dart ' ;
import ' package:provider/provider.dart ' ;
import ' package:signalr_core/signalr_core.dart ' ;
import ' package:easy_localization/easy_localization.dart ' ;
class ChatVM extends ChangeNotifier {
final ChatRepo chatRepo ;
final RequestRepo requestRepo ;
final CommonAppServices commonServices ;
ChatVM ( { required this . chatRepo , required this . requestRepo , required this . commonServices } ) ;
HubConnection ? hubConnection ;
String chatMessageText = " " ;
updateChatMessageText ( String value ) {
chatMessageText = value ;
}
clearChatMessageText ( ) {
chatMessageText = " " ;
notifyListeners ( ) ;
}
int latestOfferId = 0 ;
updateLatestOfferId ( var value ) {
latestOfferId = value ;
notifyListeners ( ) ;
}
bool acknowledgePaymentToMowaterStatus = false ;
updateAcknowledgePaymentToMowaterStatus ( var value ) {
acknowledgePaymentToMowaterStatus = value ;
notifyListeners ( ) ;
}
bool isUserOnChatScreen = false ;
final ScrollController scrollController = ScrollController ( ) ;
void scrollChatDown ( ) {
if ( ! isUserOnChatScreen ) {
return ;
}
if ( scrollController . hasClients ) {
scrollController . animateTo (
scrollController . position . maxScrollExtent + 200 , // for the text field
duration: const Duration ( seconds: 1 ) ,
curve: Curves . fastOutSlowIn ,
) ;
}
}
List < OfferRequestCommentModel > offerRejectModelList = [
OfferRequestCommentModel (
index: 0 ,
isSelected: true ,
title: LocaleKeys . itemNoLongerAvailable . tr ( ) ,
) ,
OfferRequestCommentModel (
index: 1 ,
isSelected: true ,
title: LocaleKeys . changedMind . tr ( ) ,
) ,
OfferRequestCommentModel (
index: 2 ,
isSelected: false ,
title: LocaleKeys . veryHighPrice . tr ( ) ,
) ,
OfferRequestCommentModel (
index: 3 ,
isSelected: false ,
title: LocaleKeys . alreadySold . tr ( ) ,
) ,
OfferRequestCommentModel (
index: 4 ,
isSelected: false ,
title: LocaleKeys . customerNotResponding . tr ( ) ,
) ,
OfferRequestCommentModel (
index: 5 ,
isSelected: false ,
title: LocaleKeys . otherVar . tr ( ) ,
) ,
] ;
void updateSelectionInOfferRejectModelList ( int index ) {
for ( var value in offerRejectModelList ) {
value . isSelected = false ;
}
selectedOfferRequestCommentModel = offerRejectModelList [ index ] ;
offerRejectModelList [ index ] . isSelected = true ;
notifyListeners ( ) ;
}
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel (
index: 0 ,
isSelected: true ,
title: LocaleKeys . changedMind . tr ( ) ,
) ;
String rejectOfferDescription = " " ;
String rejectOfferDescriptionError = " " ;
void updateRejectOfferDescription ( String value ) {
rejectOfferDescription = value ;
if ( value . isNotEmpty ) {
rejectOfferDescriptionError = " " ;
}
}
//REJECTING OFFER
bool isRejectOfferButtonValidated ( ) {
if ( selectedOfferRequestCommentModel . index ! = offerRejectModelList . length - 1 ) {
return true ;
}
bool isValidated = true ;
if ( rejectOfferDescription . isEmpty ) {
rejectOfferDescriptionError = GlobalConsts . descriptionError ;
isValidated = false ;
} else {
rejectOfferDescriptionError = " " ;
}
notifyListeners ( ) ;
return isValidated ;
}
Future < void > onNewMessageReceivedForRequestOffer ( { required List < ChatMessageModel > messages , bool isMyOwnOffer = false , required RequestsVM requestsVM } ) async {
if ( AppState ( ) . currentAppType = = AppType . customer ) {
for ( var currentMessage in messages ) {
log ( " currentMessage: ${ currentMessage . reqOffer ! . reqOfferImages ! . first . imageUrl } " ) ;
int providerIndex = serviceProviderOffersList . indexWhere ( ( element ) = > element . providerUserId = = currentMessage . senderUserID ) ;
if ( providerIndex ! = - 1 ) {
if ( currentMessage . chatMessageTypeEnum = = ChatMessageTypeEnum . offer ) {
for ( var chatMessage in serviceProviderOffersList [ providerIndex ] . chatMessages ! ) {
if ( chatMessage . chatMessageTypeEnum = = ChatMessageTypeEnum . offer & & chatMessage . reqOffer ! . id = = currentMessage . reqOffer ! . id ) {
chatMessage . reqOffer ! . requestOfferStatusEnum = currentMessage . reqOffer ! . requestOfferStatusEnum ;
}
}
}
serviceProviderOffersList [ providerIndex ] . chatMessages ! . add ( currentMessage ) ;
scrollChatDown ( ) ;
}
}
} else {
for ( var currentMessage in messages ) {
logger . i ( currentMessage ) ;
// Where we need to call this function for saving a message in chat we will use receiverUserID and in those cases where received ID is null , it means it is a signal R call
int requestIndex = - 1 ;
if ( isMyOwnOffer ) {
requestIndex = requestsVM . myFilteredRequests . indexWhere ( ( element ) = > ( element . customerUserID = = currentMessage . receiverUserID & & element . id = = currentMessage . requestID ) ) ;
} else {
requestIndex = requestsVM . myFilteredRequests . indexWhere ( ( element ) = > ( element . customerUserID = = currentMessage . senderUserID & & element . id = = currentMessage . requestID ) ) ;
}
log ( " requestIndex: $ requestIndex " ) ;
if ( requestIndex ! = - 1 ) {
if ( currentMessage . chatMessageTypeEnum = = ChatMessageTypeEnum . offer ) {
for ( var chatMessage in requestsVM . myFilteredRequests [ requestIndex ] . chatMessages ) {
if ( chatMessage . chatMessageTypeEnum = = ChatMessageTypeEnum . offer & & chatMessage . reqOffer ! . id = = currentMessage . reqOffer ! . id ) {
logger . i ( " chatMessage reqOfferID: ${ chatMessage . reqOffer ! . id . toString ( ) } " ) ;
logger . i ( " currentMessage reqOfferID: ${ currentMessage . reqOffer ! . id . toString ( ) } " ) ;
chatMessage . reqOffer ! . requestOfferStatusEnum = currentMessage . reqOffer ! . requestOfferStatusEnum ;
}
}
}
requestsVM . addChatMessagesInRequestsModel ( msg: currentMessage , index: requestIndex ) ;
scrollChatDown ( ) ;
}
}
}
notifyListeners ( ) ;
}
void subscribeToReceiveRequestOfferMessages ( BuildContext context ) {
hubConnection ! . on ( SignalrConsts . receiveMessageRequestOffer , ( List < Object ? > ? arguments ) {
if ( arguments = = null | | arguments . isEmpty ) return ;
List < ChatMessageModel > chat = [ ] ;
for ( var message in arguments ) {
final chatMessage = ChatMessageModel . fromJson ( message as Map < String , dynamic > , isForReqOfferImagesURLs: true ) ;
log ( " chatMessagechatMessage: ${ chatMessage . reqOffer ! . reqOfferImages ! . first . imageUrl } " ) ;
chat . add ( chatMessage ) ;
}
onNewMessageReceivedForRequestOffer ( messages: chat , requestsVM: context . read < RequestsVM > ( ) ) ;
logger . i ( arguments ) ;
// Utils.showToast(arguments.toString());
} ) ;
}
Future < bool > markMessagesAsRead ( BuildContext context , List < int > messageIds , ChatTypeEnum chatTypeEnum ) async {
bool status = false ;
try {
// Utils.showLoading(context);
status = await chatRepo . markMessageAsRead ( messageIds: messageIds , chatTypeEnum: chatTypeEnum ) ;
// Utils.hideLoading(context);
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
// Utils.hideLoading(context);
status = false ;
}
return status ;
}
Future < void > buildHubConnection ( BuildContext context ) async {
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
try {
hubConnection = await chatRepo . getHubConnection ( ) ;
await hubConnection ! . start ( ) ;
subscribeToReceiveRequestOfferMessages ( context ) ;
subscribeToReceiveAdMessages ( context ) ;
subscribeToReceiveGeneralMessages ( context ) ;
hubConnection ! . onclose ( ( exception ) {
logger . i ( " onClose: ${ exception . toString ( ) } " ) ;
buildHubConnection ( context ) ;
} ) ;
hubConnection ! . onreconnecting ( ( exception ) = > ( ) = > logger . i ( " onReconnecting: ${ exception . toString ( ) } " ) ) ;
hubConnection ! . onreconnected ( ( connectionId ) = > ( ) = > logger . i ( " onReconnected: ${ connectionId . toString ( ) } " ) ) ;
} catch ( e ) {
logger . i ( " Error: ${ e . toString ( ) } " ) ;
}
notifyListeners ( ) ;
} else {
logger . i ( " Hub Already Connected: ${ hubConnection ! . connectionId . toString ( ) } " ) ;
}
}
Future < bool > onOfferSendForRequest ( {
required String receiverId ,
required ChatMessageTypeEnum chatMessageType ,
required String message ,
required int requestId ,
required String offerPrice ,
required bool isDeliveryAvailable ,
required String serviceItemName ,
required int manufacturedById ,
required String manufacturedOn ,
required List < dynamic > offerImages ,
required BuildContext context ,
} ) async {
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
logger . i ( " Hub Not Connected!! " ) ;
await buildHubConnection ( context ) ;
}
if ( hubConnection ! . state = = HubConnectionState . connected ) {
final providerId = AppState ( ) . getUser . data ! . userInfo ! . providerId ;
final obj = < String , dynamic > {
" ReceiverUserID " : receiverId ,
" MessageType " : chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
" ChatText " : message ,
" RequestID " : requestId ,
" ReqOfferID " : 0 ,
" ReqOffer " : < String , dynamic > {
" RequestID " : requestId ,
" Price " : double . parse ( offerPrice ) ,
" IsDeliveryAvailable " : isDeliveryAvailable ,
" ServiceItem " : serviceItemName ,
" ReqOfferImages " : offerImages ,
" OfferedItemCreatedBy " : manufacturedById , // TODO: The ID should be used from the manufacturer database
// "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime
" ServiceProviderID " : providerId ,
" OfferStatus " : RequestOfferStatusEnum . offer . getIdFromRequestOfferStatusEnum ( ) ,
" Comment " : message ,
} ,
} ;
logger . i ( obj ) ;
hubConnection ! . invoke (
SignalrConsts . sendMessageRequestOffer ,
args: < Object > [ obj ] ,
) . catchError ( ( e ) {
logger . i ( " error in invoking SendMessageRequestOffer: ${ e . toString ( ) } " ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
} ) ;
}
return true ;
}
MessageImageModel convertFileToMessageImageModel ( { required File file } ) {
List < int > imageBytes = file . readAsBytesSync ( ) ;
String image = base64Encode ( imageBytes ) ;
MessageImageModel vehiclePostingImages = MessageImageModel ( imageStr: image , id: 0 , isFromNetwork: false , reqOfferID: latestOfferId , imagePath: file . path ) ;
return vehiclePostingImages ;
}
List < MessageImageModel > getMessagesImageList ( ) {
List < MessageImageModel > requestImages = [ ] ;
for ( var image in pickedImagesForMessage ) {
var value = convertFileToMessageImageModel ( file: File ( image . filePath ! ) ) ;
requestImages . add ( value ) ;
}
return requestImages ;
}
List < ImageModel > pickedImagesForMessage = [ ] ;
void removeImageFromList ( String filePath ) {
int index = pickedImagesForMessage . indexWhere ( ( element ) = > element . filePath = = filePath ) ;
if ( index = = - 1 ) {
return ;
}
pickedImagesForMessage . removeAt ( index ) ;
notifyListeners ( ) ;
}
void pickMultipleImages ( ) async {
List < ImageModel > imageModels = [ ] ;
List < File > images = await commonServices . pickMultipleImages ( ) ;
for ( var element in images ) {
imageModels . add ( ImageModel ( filePath: element . path , isFromNetwork: false ) ) ;
}
pickedImagesForMessage . addAll ( imageModels ) ;
notifyListeners ( ) ;
}
void clearPickedImagesForMessage ( ) {
pickedImagesForMessage . clear ( ) ;
notifyListeners ( ) ;
}
Future < bool > onMessageSendForRequest ( {
required String receiverId ,
required ChatMessageTypeEnum chatMessageType ,
required String message ,
required int requestId ,
required BuildContext context ,
} ) async {
if ( chatMessageType = = ChatMessageTypeEnum . freeText & & message . isEmpty ) return false ;
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
logger . i ( " Hub Not Connected!! " ) ;
await buildHubConnection ( context ) ;
}
if ( hubConnection ! . state = = HubConnectionState . connected ) {
final userId = AppState ( ) . getUser . data ! . userInfo ! . userId . toString ( ) ;
final name = AppState ( ) . getUser . data ! . userInfo ! . firstName . toString ( ) ;
List < Map < String , dynamic > > requestImagesMap = [ ] ;
List < MessageImageModel > messageImages = getMessagesImageList ( ) ;
if ( messageImages . isNotEmpty & & chatMessageType = = ChatMessageTypeEnum . image ) {
for ( var element in messageImages ) {
requestImagesMap . add ( element . toJson ( ) ) ;
}
}
final obj = < String , dynamic > {
" ReceiverUserID " : receiverId ,
" SenderUserID " : userId ,
" MessageType " : chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
" ChatText " : chatMessageType = = ChatMessageTypeEnum . image ? " ${ messageImages . length } Image(s) " : message ,
" RequestID " : requestId ,
" ReqOfferID " : latestOfferId ,
} ;
if ( chatMessageType = = ChatMessageTypeEnum . image ) {
obj . addAll ( { " ReqOfferImages " : requestImagesMap } ) ;
}
logger . i ( obj ) ;
hubConnection ! . invoke (
SignalrConsts . sendMessageRequestOffer ,
args: < Object > [ obj ] ,
) . catchError ( ( e ) {
logger . i ( " error in invoking SendMessage: ${ e . toString ( ) } " ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
} ) ;
ChatMessageModel chatMessageModel = ChatMessageModel (
messageType: chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
chatText: message ,
isMyMessage: true ,
requestID: requestId ,
senderName: name ,
senderUserID: userId ,
chatMessageTypeEnum: chatMessageType ,
receiverUserID: receiverId ,
messageImages: messageImages ,
) ;
if ( AppState ( ) . currentAppType = = AppType . customer ) {
int providerIndex = serviceProviderOffersList . indexWhere ( ( element ) = > element . providerUserId = = receiverId ) ;
if ( providerIndex ! = - 1 ) {
serviceProviderOffersList [ providerIndex ] . chatMessages ! . add ( chatMessageModel ) ;
}
} else {
int providerIndex = context . read < RequestsVM > ( ) . myFilteredRequests . indexWhere ( ( element ) = > ( element . customerUserID = = receiverId & & element . id = = requestId ) ) ;
log ( " providerIndex2: $ providerIndex " ) ;
if ( providerIndex ! = - 1 ) {
context . read < RequestsVM > ( ) . addChatMessagesInRequestsModel ( msg: chatMessageModel , index: providerIndex ) ;
}
}
return true ;
}
return false ;
}
List < ServiceProvidersOffers > serviceProviderOffersList = [ ] ;
Future < void > getOffersFromProvidersByRequest ( { required int requestId , required BuildContext context } ) async {
try {
Utils . showLoading ( context ) ;
ProviderOffersModel providerOffersModel = await requestRepo . getOffersFromProvidersByRequest ( requestId: requestId ) ;
Utils . hideLoading ( context ) ;
serviceProviderOffersList . clear ( ) ;
serviceProviderOffersList = providerOffersModel . serviceProviders ? ? [ ] ;
notifyListeners ( ) ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
}
}
Future < void > getRequestsChatMessagesForCustomer ( {
required BuildContext context ,
required int providerId ,
required int requestOfferId ,
required int requestId ,
required int providerOfferIndex ,
} ) async {
try {
int customerId = AppState ( ) . getUser . data ! . userInfo ! . customerId ! ;
Utils . showLoading ( context ) ;
List < ChatMessageModel > chatMessages = await chatRepo . getUsersChatMessagesForRequests ( providerId: providerId , customerId: customerId , requestOfferId: requestOfferId , requestId: requestId ) ;
serviceProviderOffersList [ providerOfferIndex ] . chatMessages = chatMessages ;
if ( serviceProviderOffersList [ providerOfferIndex ] . chatMessages ! = null ) {
for ( var message in serviceProviderOffersList [ providerOfferIndex ] . chatMessages ! ) {
if ( message . chatMessageTypeEnum = = ChatMessageTypeEnum . offer ) {
updateLatestOfferId ( message . reqOfferID ? ? 0 ) ;
if ( message . reqOffer ! . requestOfferStatusEnum = = RequestOfferStatusEnum . accepted ) {
context . read < RequestsVM > ( ) . updateAcceptedReqOffer ( message . reqOffer ! ) ;
context . read < RequestsVM > ( ) . updateAcceptedRequestOfferProviderName ( serviceProviderOffersList [ providerOfferIndex ] . name ? ? " " ) ;
}
log ( " latestOfferId: $ latestOfferId " ) ;
}
}
}
List < int > unreadMessageIds = [ ] ;
for ( var msg in chatMessages ) {
if ( ! msg . isRead ! & & ! msg . isMyMessage ! ) {
unreadMessageIds . add ( msg . id ! ) ;
}
}
if ( unreadMessageIds . isNotEmpty ) {
log ( " unreadMessageIds: ${ unreadMessageIds . toString ( ) } " ) ;
await markMessagesAsRead ( context , unreadMessageIds , ChatTypeEnum . requestOffer ) ;
}
Utils . hideLoading ( context ) ;
notifyListeners ( ) ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
}
}
Future < void > getRequestsChatMessagesForProvider ( {
required BuildContext context ,
required int customerId ,
required int requestOfferId ,
required int requestId ,
required int customerRequestIndex ,
} ) async {
try {
int providerId = AppState ( ) . getUser . data ! . userInfo ! . providerId ! ;
Utils . showLoading ( context ) ;
List < ChatMessageModel > chatMessages = await chatRepo . getUsersChatMessagesForRequests ( providerId: providerId , customerId: customerId , requestOfferId: requestOfferId , requestId: requestId ) ;
context . read < RequestsVM > ( ) . overwriteChatMessagesInRequestsModel ( messages: chatMessages , index: customerRequestIndex , context: context ) ;
List < int > unreadMessageIds = [ ] ;
for ( var msg in chatMessages ) {
if ( ! msg . isRead ! & & ! msg . isMyMessage ! ) {
unreadMessageIds . add ( msg . id ! ) ;
}
}
if ( unreadMessageIds . isNotEmpty ) {
await markMessagesAsRead ( context , unreadMessageIds , ChatTypeEnum . requestOffer ) ;
}
Utils . hideLoading ( context ) ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
}
}
Future < int > onActionOfferTapped ( { required BuildContext context , required RequestOfferStatusEnum requestOfferStatusEnum , required int reqOfferId , required String comments } ) async {
Utils . showLoading ( context ) ;
try {
GenericRespModel genericRespModel = await requestRepo . updateRequestOfferStatus ( requestOfferStatusEnum: requestOfferStatusEnum , requestOfferId: reqOfferId , comments: comments ) ;
Utils . showToast ( genericRespModel . message . toString ( ) ) ;
Utils . showLoading ( context ) ;
return genericRespModel . messageStatus = = 1 ? reqOfferId : - 1 ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
return - 1 ;
}
}
Future < bool > onSendMessageForActionOnRequestOffer ( {
required String receiverId ,
required ChatMessageTypeEnum chatMessageType ,
required String comments ,
required int requestId ,
required int serviceProviderID ,
required int requestOfferID ,
required String offerPrice ,
required String serviceItemName ,
required int manufacturedById ,
required String manufacturedOn ,
required RequestOfferStatusEnum requestOfferStatusEnum ,
required BuildContext context ,
} ) async {
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
logger . i ( " Hub Not Connected!! " ) ;
await buildHubConnection ( context ) ;
}
if ( hubConnection ! . state = = HubConnectionState . connected ) {
var obj = < String , dynamic > {
" ReceiverUserID " : receiverId ,
" MessageType " : chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
" ChatText " : comments ,
" RequestID " : requestId ,
" ReqOfferID " : requestOfferID ,
" ReqOffer " : < String , dynamic > {
" ID " : requestOfferID ,
" RequestID " : requestId ,
" Price " : double . parse ( offerPrice ) ,
" ServiceItem " : serviceItemName ,
" OfferedItemCreatedBy " : manufacturedById , // TODO: The ID should be used from the manufacturer database
// "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime
" ServiceProviderID " : serviceProviderID ,
" OfferStatus " : requestOfferStatusEnum . getIdFromRequestOfferStatusEnum ( ) ,
" Comment " : comments ,
} ,
} ;
logger . i ( obj ) ;
hubConnection ! . invoke (
SignalrConsts . sendMessageRequestOffer ,
args: < Object > [ obj ] ,
) . catchError ( ( e ) {
logger . i ( " error in invoking SendMessageRequestOffer: ${ e . toString ( ) } " ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
} ) ;
}
return true ;
}
// =================== Ads ======================
List < ChatMessageModel > currentMessagesForAds = [ ] ;
Future < void > getUsersChatMessagesForAd ( { required BuildContext context , int ? adID , int ? adsChatBuyerId , String ? userID , String ? senderName , required bool isForBuyer } ) async {
try {
Utils . showLoading ( context ) ;
currentMessagesForAds = await chatRepo . getUsersChatMessagesForAds ( userID: userID , adID: adID , isForBuyer: isForBuyer , adsChatBuyerId: adsChatBuyerId ) ;
Utils . hideLoading ( context ) ;
List < int > unreadMessageIds = [ ] ;
for ( var msg in currentMessagesForAds ) {
msg . senderName = senderName ? ? " " ;
if ( ! msg . isRead ! & & ! msg . isMyMessage ! ) {
unreadMessageIds . add ( msg . id ! ) ;
}
}
if ( unreadMessageIds . isNotEmpty ) {
await markMessagesAsRead ( context , unreadMessageIds , ChatTypeEnum . ads ) ;
}
notifyListeners ( ) ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
}
}
void subscribeToReceiveAdMessages ( BuildContext context ) {
hubConnection ! . on ( SignalrConsts . receiveMessageAds , ( List < Object ? > ? arguments ) {
if ( arguments = = null | | arguments . isEmpty ) return ;
List < ChatMessageModel > chat = [ ] ;
for ( var message in arguments ) {
final chatMessage = ChatMessageModel . fromJson ( message as Map < String , dynamic > ) ;
chat . add ( chatMessage ) ;
}
onNewMessageReceivedForAds ( messages: chat ) ;
logger . i ( arguments ) ;
// Utils.showToast(arguments.toString());
} ) ;
}
Future < void > onNewMessageReceivedForAds ( { required List < ChatMessageModel > messages } ) async {
for ( var msg in messages ) {
currentMessagesForAds . add ( msg ) ;
}
scrollChatDown ( ) ;
notifyListeners ( ) ;
}
Future < bool > onTextMessageSendForAds ( {
required String receiverId ,
required ChatMessageTypeEnum chatMessageType ,
required String message ,
required int adId ,
required BuildContext context ,
} ) async {
if ( message . isEmpty ) return false ;
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
logger . i ( " Hub Not Connected!! " ) ;
await buildHubConnection ( context ) ;
}
if ( hubConnection ! . state = = HubConnectionState . connected ) {
final userId = AppState ( ) . getUser . data ! . userInfo ! . userId . toString ( ) ;
final name = AppState ( ) . getUser . data ! . userInfo ! . firstName . toString ( ) ;
final obj = < String , dynamic > {
" ReceiverUserID " : receiverId ,
// "SenderUserID": userId,
" MessageType " : chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
" ChatText " : message ,
" AdsID " : adId ,
} ;
logger . i ( " $ obj " ) ;
hubConnection ! . invoke (
SignalrConsts . sendMessageAds ,
args: < Object > [ obj ] ,
) . catchError ( ( e ) {
logger . i ( " error in invoking SendMessage: ${ e . toString ( ) } " ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
} ) ;
ChatMessageModel chatMessageModel = ChatMessageModel (
messageType: chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
chatText: message ,
isMyMessage: true ,
senderName: name ,
senderUserID: userId ,
chatMessageTypeEnum: ChatMessageTypeEnum . freeText ,
receiverUserID: receiverId ,
) ;
currentMessagesForAds . add ( chatMessageModel ) ;
notifyListeners ( ) ;
if ( AppState ( ) . currentAppType = = AppType . customer ) {
} else { }
return true ;
}
return false ;
}
// ========================General ==================
List < ChatMessageModel > currentMessagesForGeneralChat = [ ] ;
Future < void > getUsersChatMessagesForGeneralChat ( { required BuildContext context , int ? adID , int ? adsChatBuyerId , String ? userID , String ? senderName , required bool isForBuyer } ) async {
try {
Utils . showLoading ( context ) ;
currentMessagesForGeneralChat = await chatRepo . getUsersChatMessagesForGeneralChat ( userID: userID , adID: adID , isForBuyer: isForBuyer , adsChatBuyerId: adsChatBuyerId ) ;
Utils . hideLoading ( context ) ;
List < int > unreadMessageIds = [ ] ;
for ( var msg in currentMessagesForGeneralChat ) {
msg . senderName = senderName ? ? " " ;
if ( ! msg . isRead ! & & ! msg . isMyMessage ! ) {
unreadMessageIds . add ( msg . id ! ) ;
}
}
if ( unreadMessageIds . isNotEmpty ) {
await markMessagesAsRead ( context , unreadMessageIds , ChatTypeEnum . general ) ;
}
notifyListeners ( ) ;
} catch ( e ) {
logger . i ( e . toString ( ) ) ;
Utils . showToast ( e . toString ( ) ) ;
Utils . hideLoading ( context ) ;
}
}
Future < void > onNewMessageReceivedForGeneral ( { required List < ChatMessageModel > messages } ) async {
for ( var msg in messages ) {
currentMessagesForAds . add ( msg ) ;
}
scrollChatDown ( ) ;
notifyListeners ( ) ;
}
void subscribeToReceiveGeneralMessages ( BuildContext context ) {
hubConnection ! . on ( SignalrConsts . receiveMessageGeneral , ( List < Object ? > ? arguments ) {
if ( arguments = = null | | arguments . isEmpty ) return ;
List < ChatMessageModel > chat = [ ] ;
for ( var message in arguments ) {
final chatMessage = ChatMessageModel . fromJson ( message as Map < String , dynamic > ) ;
chat . add ( chatMessage ) ;
}
onNewMessageReceivedForGeneral ( messages: chat ) ;
logger . i ( arguments ) ;
// Utils.showToast(arguments.toString());
} ) ;
}
Future < bool > onTextMessageSendForGeneralChat ( {
required String receiverId ,
required ChatMessageTypeEnum chatMessageType ,
required String message ,
required int adId ,
required BuildContext context ,
} ) async {
if ( message . isEmpty ) return false ;
if ( hubConnection = = null | | hubConnection ! . state ! = HubConnectionState . connected ) {
logger . i ( " Hub Not Connected!! " ) ;
await buildHubConnection ( context ) ;
}
if ( hubConnection ! . state = = HubConnectionState . connected ) {
final userId = AppState ( ) . getUser . data ! . userInfo ! . userId . toString ( ) ;
final name = AppState ( ) . getUser . data ! . userInfo ! . firstName . toString ( ) ;
final obj = < String , dynamic > {
" ReceiverUserID " : receiverId ,
" MessageType " : chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
" ChatText " : message ,
} ;
logger . i ( " $ obj " ) ;
hubConnection ! . invoke (
SignalrConsts . sendMessageGeneral ,
args: < Object > [ obj ] ,
) . catchError ( ( e ) {
logger . i ( " error in invoking SendMessage: ${ e . toString ( ) } " ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
} ) ;
ChatMessageModel chatMessageModel = ChatMessageModel (
messageType: chatMessageType . getIdFromChatMessageTypeEnum ( ) ,
chatText: message ,
isMyMessage: true ,
senderName: name ,
senderUserID: userId ,
chatMessageTypeEnum: ChatMessageTypeEnum . freeText ,
receiverUserID: receiverId ,
) ;
currentMessagesForGeneralChat . add ( chatMessageModel ) ;
notifyListeners ( ) ;
if ( AppState ( ) . currentAppType = = AppType . customer ) {
} else { }
return true ;
}
return false ;
}
}