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.
car_common_app/lib/view_models/chat_view_model.dart

554 lines
19 KiB
Dart

// ignore_for_file: use_build_context_synchronously
import 'dart:developer';
2 years ago
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';
1 year ago
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';
2 years ago
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';
2 years ago
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';
1 year ago
import 'package:easy_localization/easy_localization.dart';
2 years ago
class ChatVM extends ChangeNotifier {
2 years ago
final ChatRepo chatRepo;
final RequestRepo requestRepo;
2 years ago
ChatVM({required this.chatRepo, required this.requestRepo});
2 years ago
HubConnection? hubConnection;
2 years ago
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,
1 year ago
title: LocaleKeys.changedMind.tr(),
),
OfferRequestCommentModel(
index: 1,
isSelected: false,
1 year ago
title: LocaleKeys.veryHighPrice.tr(),
),
OfferRequestCommentModel(
index: 2,
isSelected: false,
1 year ago
title: LocaleKeys.alreadySold.tr(),
),
OfferRequestCommentModel(
index: 3,
isSelected: true,
1 year ago
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();
}
2 years ago
}
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);
2 years ago
}
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],
2 years ago
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
2 years ago
Utils.showToast(e.toString());
return false;
2 years ago
});
}
return true;
2 years ago
}
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, 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) {
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;
}
2 years ago
}