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.
554 lines
19 KiB
Dart
554 lines
19 KiB
Dart
// 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/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/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';
|
|
import 'package:easy_localization/easy_localization.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();
|
|
}
|
|
|
|
bool isUserOnChatScreen = false;
|
|
|
|
final ScrollController scrollController = ScrollController();
|
|
|
|
void scrollChatDown() {
|
|
if (!isUserOnChatScreen) {
|
|
return;
|
|
}
|
|
|
|
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: false,
|
|
title: LocaleKeys.changedMind.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 1,
|
|
isSelected: false,
|
|
title: LocaleKeys.veryHighPrice.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 2,
|
|
isSelected: false,
|
|
title: LocaleKeys.alreadySold.tr(),
|
|
),
|
|
OfferRequestCommentModel(
|
|
index: 3,
|
|
isSelected: true,
|
|
title: LocaleKeys.otherVar.tr(),
|
|
),
|
|
];
|
|
|
|
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel(
|
|
index: 3,
|
|
isSelected: true,
|
|
title: LocaleKeys.otherVar.tr(),
|
|
);
|
|
|
|
void updateSelectionInOfferRejectModelList(int index) {
|
|
for (var value in offerRejectModelList) {
|
|
value.isSelected = false;
|
|
}
|
|
selectedOfferRequestCommentModel = offerRejectModelList[index];
|
|
offerRejectModelList[index].isSelected = true;
|
|
notifyListeners();
|
|
}
|
|
|
|
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 msg in messages) {
|
|
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID);
|
|
if (providerIndex != -1) {
|
|
serviceProviderOffersList[providerIndex].chatMessages!.add(msg);
|
|
scrollChatDown();
|
|
}
|
|
}
|
|
} else {
|
|
for (var msg in messages) {
|
|
logger.i(msg);
|
|
// 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 = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.receiverUserID && element.id == msg.requestID));
|
|
} else {
|
|
providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.senderUserID && element.id == msg.requestID));
|
|
}
|
|
log("providerIndex: $providerIndex");
|
|
if (providerIndex != -1) {
|
|
requestsVM.addChatMessagesInRequestsModel(msg: msg, index: providerIndex);
|
|
scrollChatDown();
|
|
}
|
|
}
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async {
|
|
for (var msg in messages) {
|
|
currentMessagesForAds.add(msg);
|
|
}
|
|
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>);
|
|
chat.add(chatMessage);
|
|
}
|
|
onNewMessageReceivedForRequestOffer(messages: chat, requestsVM: context.read<RequestsVM>());
|
|
logger.i(arguments);
|
|
// Utils.showToast(arguments.toString());
|
|
});
|
|
}
|
|
|
|
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> buildHubConnection(BuildContext context) async {
|
|
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
|
|
try {
|
|
hubConnection = await chatRepo.getHubConnection();
|
|
await hubConnection!.start();
|
|
subscribeToReceiveRequestOfferMessages(context);
|
|
subscribeToReceiveAdMessages(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();
|
|
}
|
|
}
|
|
|
|
Future<bool> onOfferSendForRequest({
|
|
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) {
|
|
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),
|
|
"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;
|
|
}
|
|
|
|
Future<bool> onTextMessageSendForRequest({
|
|
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) {
|
|
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,
|
|
"RequestID": requestId,
|
|
"ReqOfferID": latestOfferId,
|
|
// "ReqOffer": {}
|
|
};
|
|
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: 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<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> 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<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);
|
|
log("latestOfferId: $latestOfferId");
|
|
}
|
|
}
|
|
}
|
|
Utils.hideLoading(context);
|
|
notifyListeners();
|
|
} catch (e) {
|
|
logger.i(e.toString());
|
|
Utils.showToast(e.toString());
|
|
Utils.hideLoading(context);
|
|
}
|
|
}
|
|
|
|
Future<void> 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<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessagesForRequests(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
|
|
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context);
|
|
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 {
|
|
try {
|
|
GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId, comments: comments);
|
|
Utils.showToast(genericRespModel.message.toString());
|
|
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 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),
|
|
"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!) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
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<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;
|
|
}
|
|
}
|