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.
919 lines
32 KiB
Dart
919 lines
32 KiB
Dart
// ignore_for_file: use_build_context_synchronously
|
|
|
|
import 'dart:convert';
|
|
import 'dart:developer';
|
|
import 'dart:io';
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
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/base_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';
|
|
|
|
class ChatVM extends BaseVM {
|
|
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> dealOptionsModelList = [
|
|
OfferRequestCommentModel(
|
|
index: 0,
|
|
isSelected: false,
|
|
title: LocaleKeys.dealCompleted.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 1,
|
|
isSelected: false,
|
|
title: LocaleKeys.theDealNotCompleted.tr(),
|
|
),
|
|
];
|
|
|
|
updateIsSelectedInDealOptionsModelList(int index, bool value) {
|
|
for (var element in dealOptionsModelList) {
|
|
element.isSelected = false;
|
|
}
|
|
dealOptionsModelList[index].isSelected = true;
|
|
notifyListeners();
|
|
}
|
|
|
|
List<int> indexesForCancelSpecialCarOffer = [0, 1, 6, 10];
|
|
List<int> indexesForCancelSparePartOffer = [2, 10];
|
|
List<int> indexesForRejectOffer = [3, 4, 10];
|
|
List<int> indexesForDealNotCompleted = [7, 4, 8, 9, 10];
|
|
|
|
List<OfferRequestCommentModel> offerRejectModelList = [
|
|
OfferRequestCommentModel(
|
|
index: 0,
|
|
isSelected: true,
|
|
title: LocaleKeys.dealOutsideApp.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 1,
|
|
isSelected: false,
|
|
title: LocaleKeys.noAgreementCustomer.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 2,
|
|
isSelected: false,
|
|
title: LocaleKeys.itemNoLongerAvailable.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 3,
|
|
isSelected: true,
|
|
title: LocaleKeys.changedMind.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 4,
|
|
isSelected: false,
|
|
title: LocaleKeys.veryHighPrice.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 5,
|
|
isSelected: false,
|
|
title: LocaleKeys.alreadySold.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 6,
|
|
isSelected: false,
|
|
title: LocaleKeys.customerNotResponding.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 7,
|
|
isSelected: false,
|
|
title: LocaleKeys.cancelRequest.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 8,
|
|
isSelected: false,
|
|
title: LocaleKeys.offerNotMatched.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 9,
|
|
isSelected: false,
|
|
title: LocaleKeys.testTheService.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 10,
|
|
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) {
|
|
logger.i(currentMessage);
|
|
|
|
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) {
|
|
logger.i(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);
|
|
chat.add(chatMessage);
|
|
}
|
|
onNewMessageReceivedForRequestOffer(messages: chat, requestsVM: context.read<RequestsVM>());
|
|
// 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;
|
|
}
|
|
|
|
int _retryCount = 0;
|
|
final int _maxRetries = 5; // Maximum number of retries
|
|
bool _isReconnecting = false;
|
|
|
|
Future<void> _reconnectWithBackoff(BuildContext context) async {
|
|
if (_retryCount >= _maxRetries) {
|
|
logger.e("Maximum retry attempts reached. Stopping reconnection.");
|
|
return;
|
|
}
|
|
|
|
final delay = Duration(seconds: 2 * (_retryCount + 1)); // Exponential backoff
|
|
logger.i("Retrying connection in ${delay.inSeconds} seconds...");
|
|
await Future.delayed(delay);
|
|
|
|
_retryCount++;
|
|
await buildHubConnection(context); // Try reconnecting
|
|
}
|
|
|
|
Future<void> buildHubConnection(BuildContext context) async {
|
|
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
|
|
if (_isReconnecting) {
|
|
logger.i("Reconnection already in progress");
|
|
return;
|
|
}
|
|
|
|
if (_isReconnecting) {
|
|
logger.i("Reconnection already in progress");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
_isReconnecting = true;
|
|
|
|
hubConnection = await chatRepo.getHubConnection();
|
|
await hubConnection!.start();
|
|
|
|
// Reset retry count on successful connection
|
|
_retryCount = 0;
|
|
_isReconnecting = false;
|
|
|
|
// Subscribe to messages
|
|
_subscribeToReceiveRequestOfferMessages(context);
|
|
_subscribeToReceiveAdMessages(context);
|
|
_subscribeToReceiveGeneralMessages(context);
|
|
|
|
// Configure handlers
|
|
hubConnection!.onclose((exception) async {
|
|
logger.i("onClose: ${exception.toString()}");
|
|
await _reconnectWithBackoff(context);
|
|
});
|
|
|
|
hubConnection!.onreconnecting((exception) {
|
|
logger.i("onReconnecting: ${exception?.toString()}");
|
|
});
|
|
|
|
hubConnection!.onreconnected((connectionId) {
|
|
logger.i("onReconnected: ${connectionId.toString()}");
|
|
});
|
|
} catch (e) {
|
|
logger.e("Error during hub connection setup: ${e.toString()}");
|
|
_isReconnecting = false; // Reset on failure
|
|
}
|
|
|
|
notifyListeners();
|
|
} else {
|
|
logger.i("Hub Already Connected: ${hubConnection!.connectionId.toString()}");
|
|
}
|
|
}
|
|
|
|
Future<void> closeHubConnection() async {
|
|
if (hubConnection != null && hubConnection!.state == HubConnectionState.connected) {
|
|
hubConnection!.stop();
|
|
}
|
|
}
|
|
|
|
Future<bool> onOfferSendForRequest({
|
|
required String receiverId,
|
|
required ChatMessageTypeEnum chatMessageType,
|
|
required String message,
|
|
required int requestId,
|
|
required String offerPrice,
|
|
required bool isDeliveryAvailable,
|
|
required RequestDeliveryOptionEnum offerDeliveryOption,
|
|
required String serviceItemName,
|
|
required String manufacturedByName,
|
|
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,
|
|
"OfferDeliveryOption": offerDeliveryOption.getIdRequestDeliveryOptionEnum(),
|
|
"ServiceItem": serviceItemName,
|
|
"ReqOfferImages": offerImages,
|
|
"OfferedItemCreatedByName": manufacturedByName,
|
|
// "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);
|
|
if (pickedImagesForMessage.length > GlobalConsts.maxFileCount) {
|
|
pickedImagesForMessage = pickedImagesForMessage.sublist(0, GlobalConsts.maxFileCount);
|
|
Utils.showToast(LocaleKeys.maxFileSelection);
|
|
}
|
|
|
|
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, bool isNeedLoading = true}) async {
|
|
try {
|
|
if (isNeedLoading) {
|
|
setState(ViewState.busy);
|
|
}
|
|
ProviderOffersModel providerOffersModel = await requestRepo.getOffersFromProvidersByRequest(requestId: requestId);
|
|
if (isNeedLoading) {
|
|
setState(ViewState.idle);
|
|
}
|
|
serviceProviderOffersList.clear();
|
|
serviceProviderOffersList = providerOffersModel.serviceProviders ?? [];
|
|
notifyListeners();
|
|
} catch (e) {
|
|
logger.i(e.toString());
|
|
Utils.showToast(e.toString());
|
|
if (isNeedLoading) {
|
|
setState(ViewState.idle);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
await 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.hideLoading(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 bool isDeliveryAvailable,
|
|
required RequestDeliveryOptionEnum offerDeliveryOption,
|
|
required String serviceItemName,
|
|
required String manufacturedByName,
|
|
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,
|
|
"OfferedItemCreatedByName": manufacturedByName,
|
|
"IsDeliveryAvailable": isDeliveryAvailable,
|
|
"OfferDeliveryOption": offerDeliveryOption.getIdRequestDeliveryOptionEnum(),
|
|
// We have commented this because Backend Team is using their server time for this. It was the time offer created by
|
|
// "OfferedItemCreatedOn": manufacturedOn,
|
|
"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;
|
|
}
|
|
}
|