// ignore_for_file: use_build_context_synchronously import 'dart:developer'; 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/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/utils/enums.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:provider/provider.dart'; import 'package:signalr_core/signalr_core.dart'; class ChatVM extends ChangeNotifier { final ChatRepo chatRepo; final RequestRepo requestRepo; ChatVM({required this.chatRepo, required this.requestRepo}); HubConnection? hubConnection; String chatMessageText = ""; updateChatMessageText(String value) { chatMessageText = value; } clearChatMessageText() { chatMessageText = ""; notifyListeners(); } int latestOfferId = 0; updateLatestOfferId(var value) { latestOfferId = value; notifyListeners(); } List offerRejectModelList = [ OfferRequestCommentModel( index: 0, isSelected: false, title: "I have changed my mind.", ), OfferRequestCommentModel( index: 1, isSelected: false, title: "Very High Price.", ), OfferRequestCommentModel( index: 2, isSelected: false, title: "Already Sold", ), OfferRequestCommentModel( index: 3, isSelected: true, title: "Other", ), ]; void updateSelectionInOfferRejectModelList(int index) { for (var value in offerRejectModelList) { value.isSelected = false; } offerRejectModelList[index].isSelected = true; notifyListeners(); } String rejectOfferDescription = ""; String rejectOfferDescriptionError = ""; void updateRejectOfferDescription(String value) { rejectOfferDescription = value; if (value.isNotEmpty) { rejectOfferDescriptionError = ""; } } //REJECTING OFFER bool isRejectOfferButtonValidated() { bool isValidated = true; if (rejectOfferDescription.isEmpty) { rejectOfferDescriptionError = GlobalConsts.descriptionError; isValidated = false; } else { rejectOfferDescriptionError = ""; } notifyListeners(); return isValidated; } Future onNewMessageReceived({required List messages, required BuildContext context, bool isMyOwnOffer = false}) async { // log("message I received in onNewMessageReceived ${messages.first.toString()}"); if (AppState().currentAppType == AppType.customer) { for (var msg in messages) { int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID); if (providerIndex != -1) { serviceProviderOffersList[providerIndex].chatMessages!.add(msg); } } } else { for (var msg in messages) { // 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 providerIndex = -1; if (isMyOwnOffer) { providerIndex = context.read().myFilteredRequests.indexWhere( (element) => element.customerUserID == msg.receiverUserID, ); } else { providerIndex = context.read().myFilteredRequests.indexWhere( (element) => element.customerUserID == msg.senderUserID, ); } // log("here is it: $providerIndex"); // log("here is it: ${msg.senderUserID}"); // log("here is it: ${context.read().myFilteredRequests.first.customerUserID.toString()}"); if (providerIndex != -1) { context.read().addChatMessagesInRequestsModel(msg: msg, index: providerIndex); } } } notifyListeners(); } Future buildHubConnection(BuildContext context) async { if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { try { hubConnection = await chatRepo.getHubConnection(); await hubConnection!.start(); hubConnection!.on("ReceiveMessageRequestOffer", (List? arguments) { if (arguments == null || arguments.isEmpty) return; List chat = []; for (var message in arguments) { final chatMessage = ChatMessageModel.fromJson(message as Map); chat.add(chatMessage); } onNewMessageReceived(messages: chat, context: context); logger.i("I received ping : ${arguments.toString()}"); }); } catch (e) { logger.i("Error: ${e.toString()}"); } notifyListeners(); } } Future onSendMessageForRequestOffer({ required String receiverId, required ChatMessageTypeEnum chatMessageType, required String message, required int requestId, required String offerPrice, required BuildContext context, }) async { if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { await buildHubConnection(context); } if (hubConnection!.state == HubConnectionState.connected) { final providerId = AppState().getUser.data!.userInfo!.providerId; hubConnection!.invoke( "SendMessageRequestOffer", args: [ { "ReceiverUserID": receiverId, "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "ChatText": message, "RequestID": requestId, "ReqOfferID": 0, "ReqOffer": { "RequestID": requestId, "Price": double.parse(offerPrice), "ServiceProviderID": providerId, "OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), "Comment": message, }, } ], ).catchError((e) { logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}"); Utils.showToast(e.toString()); return false; }); } return true; } Future onTextMessageSend({ required String receiverId, required ChatMessageTypeEnum chatMessageType, required String message, required int requestId, required String offerPrice, required BuildContext context, }) async { if (message.isEmpty) return false; if (hubConnection == null || hubConnection!.state != HubConnectionState.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(); log("I have saved this: ${({ "ReceiverUserID": receiverId, "SenderUserID": userId, "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "ChatText": message, "RequestID": requestId, "ReqOfferID": latestOfferId, }).toString()}"); hubConnection!.invoke( "SendMessageRequestOffer", args: [ { "ReceiverUserID": receiverId, "SenderUserID": userId, "MessageType": chatMessageType.getIdFromChatMessageTypeEnum(), "ChatText": message, "RequestID": requestId, "ReqOfferID": latestOfferId, } ], ).catchError((e) { logger.i("error in invoking SendMessageRequestOffer: ${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: ChatMessageTypeEnum.freeText, receiverUserID: receiverId, ); 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().myFilteredRequests.indexWhere((element) => element.customerUserID == receiverId); if (providerIndex != -1) { context.read().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex); } } return true; } return false; } List serviceProviderOffersList = []; Future 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 getUsersChatMessagesForCustomer({ 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 chatMessages = await chatRepo.getUsersChatMessages(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); log("latestOfferId: $latestOfferId"); } } } Utils.hideLoading(context); notifyListeners(); } catch (e) { logger.i(e.toString()); Utils.showToast(e.toString()); Utils.hideLoading(context); } } Future getUsersChatMessagesForProvider({ 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 chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId); context.read().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex); Utils.hideLoading(context); } catch (e) { logger.i(e.toString()); Utils.showToast(e.toString()); Utils.hideLoading(context); } } Future onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId}) async { try { Utils.showLoading(context); GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId); Utils.hideLoading(context); return genericRespModel.messageStatus == 1 ? reqOfferId : -1; } catch (e) { logger.i(e.toString()); Utils.showToast(e.toString()); Utils.hideLoading(context); return -1; } } }