Chat Implementation 1.0

mirza_development
Faiz Hashmi 2 years ago
parent 6245aa9ef4
commit 837191a5e1

@ -132,9 +132,13 @@ class ApiConsts {
static String createRequest = "${baseUrlServices}api/RequestManagement/Request_Create";
static String getRequest = "${baseUrlServices}api/RequestManagement/Request_Get";
static String getRequestOffers = "${baseUrlServices}api/RequestManagement/ReqOffer_Get";
static String updateRequestOffer = "${baseUrlServices}api/RequestManagement/RequestOffer_UpdateStatus";
static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get";
//Chat
static String chatHubUrl = "$baseUrlServices/McHub";
static String messageIsReadUpdate = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update";
static String getChatMessages = "${baseUrlServices}api/RequestManagement/ReqOfferChat_Get";
static List<String> closingUrls = ["PayFortResponse"];
}

@ -1,4 +1,5 @@
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -110,17 +111,28 @@ class AppRoutes {
}
class ChatViewArguments {
final RequestModel? requestModel;
final int? requestId;
final ChatTypeEnum chatTypeEnum;
final String senderId;
final String receiverId;
final int providerIndex;
final int requestIndex;
ChatViewArguments({required this.chatTypeEnum, this.requestModel, required this.senderId, required this.receiverId});
ChatViewArguments({required this.chatTypeEnum, this.requestId, required this.senderId, required this.receiverId, required this.providerIndex, required this.requestIndex});
}
class OfferListPageArguments {
final List<OffersModel> offersList;
final RequestModel? requestModel;
final List<ServiceProvidersOffers> serviceProviderOffers;
final int? requestId;
OfferListPageArguments({required this.serviceProviderOffers, this.requestId});
}
class RequestDetailPageArguments {
final int requestIndex;
final RequestModel requestModel;
OfferListPageArguments({required this.offersList, this.requestModel});
RequestDetailPageArguments({required this.requestIndex, required this.requestModel});
}

@ -1,103 +0,0 @@
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class ChatMessageModel {
String? senderUserID;
String? senderName;
int? messageType;
ChatMessageTypeEnum? messageTypeEnum;
String? message;
RequestOffer? requestOffer;
int? requestID;
int? requestOfferID;
bool? isMyMessage;
ChatMessageModel({
this.senderUserID,
this.senderName,
this.messageType,
this.message,
this.requestOffer,
this.requestID,
this.requestOfferID,
this.isMyMessage = true,
});
ChatMessageModel.fromJson(Map<String, dynamic> json) {
final myUserId = AppState().getUser.data!.userInfo!.userId.toString();
senderUserID = json['senderUserID'];
senderName = json['senderName'];
messageType = json['messageType'];
messageTypeEnum = (json['messageType'] as int).toChatMessageTypeEnum();
message = json['message'];
requestOffer = json['requestOffer'] != null ? RequestOffer.fromJson(json['requestOffer']) : null;
requestID = json['requestID'];
requestOfferID = json['requestOfferID'];
isMyMessage = (json['senderUserId']).toString() == myUserId;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['senderUserID'] = senderUserID;
data['senderName'] = senderName;
data['messageType'] = messageType;
data['message'] = message;
if (requestOffer != null) {
data['requestOffer'] = requestOffer!.toJson();
}
data['requestID'] = requestID;
data['requestOfferID'] = requestOfferID;
return data;
}
}
class RequestOffer {
int? id;
int? requestID;
int? serviceProviderID;
int? offerStatus;
RequestOfferStatusEnum? requestOfferStatusEnum;
String? comment;
double? price;
String? offeredItemCreatedBy;
String? offeredItemCreatedOn;
RequestOffer({
this.id,
this.requestID,
this.serviceProviderID,
this.offerStatus,
this.comment,
this.price,
this.offeredItemCreatedBy,
this.offeredItemCreatedOn,
this.requestOfferStatusEnum = RequestOfferStatusEnum.offer,
});
RequestOffer.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];
offerStatus = json['offerStatus'];
offerStatus = json['offerStatus'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
comment = json['comment'];
price = json['price'];
offeredItemCreatedBy = json['offeredItemCreatedBy'];
offeredItemCreatedOn = json['offeredItemCreatedOn'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['requestID'] = requestID;
data['serviceProviderID'] = serviceProviderID;
data['offerStatus'] = offerStatus;
data['comment'] = comment;
data['price'] = price;
data['offeredItemCreatedBy'] = offeredItemCreatedBy;
data['offeredItemCreatedOn'] = offeredItemCreatedOn;
return data;
}
}

@ -0,0 +1,96 @@
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class ChatMessageModel {
int? id;
String? senderUserID;
String? senderName;
int? messageType;
ChatMessageTypeEnum? chatMessageTypeEnum;
String? chatText;
int? requestID;
int? reqOfferID;
int? serviceProviderID;
int? offerStatus;
ReqOffer? reqOffer;
bool? isRead;
String? readOn;
bool? isMyMessage;
ChatMessageModel({
this.id,
this.senderUserID,
this.senderName,
this.messageType,
this.chatMessageTypeEnum,
this.chatText,
this.requestID,
this.reqOfferID,
this.serviceProviderID,
this.offerStatus,
this.reqOffer,
this.isRead,
this.readOn,
this.isMyMessage,
});
ChatMessageModel.fromJson(Map<String, dynamic> json) {
final myUserId = AppState().getUser.data!.userInfo!.userId.toString();
id = json['id'];
senderUserID = json['senderUserID'];
senderName = json['senderName'];
messageType = json['messageType'];
chatMessageTypeEnum = (json['messageType'] as int).toChatMessageTypeEnum();
chatText = json['chatText'];
requestID = json['requestID'];
reqOfferID = json['reqOfferID'];
serviceProviderID = json['serviceProviderID'];
offerStatus = json['offerStatus'];
reqOffer = json['reqOffer'] != null ? ReqOffer.fromJson(json['reqOffer']) : null;
isRead = json['isRead'];
readOn = json['readOn'];
isMyMessage = (json['senderUserId']).toString() == myUserId;
}
}
class ReqOffer {
int? id;
int? requestID;
int? serviceProviderID;
int? offerStatus;
String? offerStatusText;
String? comment;
double? price;
RequestOfferStatusEnum? requestOfferStatusEnum;
ReqOffer({
this.id,
this.requestID,
this.serviceProviderID,
this.offerStatus,
this.offerStatusText,
this.comment,
this.price,
this.requestOfferStatusEnum,
});
ReqOffer.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];
offerStatus = json['offerStatus'];
offerStatusText = json['offerStatusText'];
comment = json['comment'];
price = json['price'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
}
}
class OfferRequestCommentModel {
int? index;
String? title;
bool? isSelected;
OfferRequestCommentModel({this.index, this.title, this.isSelected});
}

@ -0,0 +1,77 @@
import 'dart:developer';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
class ProviderOffersModel {
int? id;
int? customerID;
int? requestType;
int? requestStatus;
String? brand;
String? model;
int? year;
bool? isNew;
String? description;
double? price;
int? spOfferCount;
List<ServiceProvidersOffers>? serviceProviders;
ProviderOffersModel({
this.id,
this.customerID,
this.requestType,
this.requestStatus,
this.brand,
this.model,
this.year,
this.isNew,
this.description,
this.price,
this.spOfferCount,
this.serviceProviders,
});
ProviderOffersModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
customerID = json['customerID'];
requestType = json['requestType'];
requestStatus = json['requestStatus'];
brand = json['brand'];
model = json['model'];
year = json['year'];
isNew = json['isNew'];
description = json['description'];
price = json['price'];
spOfferCount = json['spOfferCount'];
if (json['serviceProviders'] != null) {
serviceProviders = <ServiceProvidersOffers>[];
json['serviceProviders'].forEach((v) {
serviceProviders!.add(ServiceProvidersOffers.fromJson(v));
});
}
}
}
class ServiceProvidersOffers {
String? providerUserId;
int? providerId;
String? name;
String? mobileNo;
String? email;
String? companyName;
int? offerCount;
List<ChatMessageModel>? chatMessages;
ServiceProvidersOffers({this.providerId, this.name, this.mobileNo, this.email, this.companyName, this.offerCount, this.chatMessages, this.providerUserId});
ServiceProvidersOffers.fromJson(Map<String, dynamic> json) {
providerId = json['providerId'];
providerUserId = json['providerUserId'] ?? "c680271c-b2a7-4ecf-7e95-08db545aec1b"; //TODO Remove this when parameter is added in backend
name = json['name'];
mobileNo = json['mobileNo'];
email = json['email'];
companyName = json['companyName'];
offerCount = json['offerCount'];
chatMessages = [];
}
}

@ -1,4 +1,5 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class RequestModel {
@ -34,6 +35,7 @@ class RequestModel {
DateTime createdOn;
dynamic modifiedBy;
dynamic modifiedOn;
List<ChatMessageModel> chatMessages;
RequestModel({
required this.requestType,
@ -68,6 +70,7 @@ class RequestModel {
required this.createdOn,
required this.modifiedBy,
required this.modifiedOn,
required this.chatMessages,
});
factory RequestModel.fromJson(Map<String, dynamic> json) {
@ -104,40 +107,7 @@ class RequestModel {
createdOn: DateTime.parse(json["createdOn"]),
modifiedBy: json["modifiedBy"],
modifiedOn: json["modifiedOn"],
chatMessages: [],
);
}
Map<String, dynamic> toJson() => {
"requestType": requestType,
"requestTypeName": requestTypeName,
"requestStatusName": requestStatusName,
"requestStatus": requestStatus,
"cityName": cityName,
"vehicleTypeName": vehicleTypeName,
"countryName": countryName,
"customerName": customerName,
"serviceProviders": serviceProviders,
"offerCount": offerCount,
"id": id,
"customerID": customerId,
"customer": customer,
"brand": brand,
"model": model,
"year": year,
"isNew": isNew,
"description": description,
"requestImages": List<dynamic>.from(requestImages.map((x) => x)),
"cityID": cityId,
"city": city,
"price": price,
"paymentStatus": paymentStatus,
"vehicleTypeID": vehicleTypeId,
"countryID": countryId,
"requestProviderItem": List<dynamic>.from(requestProviderItem.map((x) => x)),
"isActive": isActive,
"createdBy": createdBy,
"createdOn": createdOn.toIso8601String(),
"modifiedBy": modifiedBy,
"modifiedOn": modifiedOn,
};
}

@ -1,14 +1,27 @@
import 'dart:developer';
import 'dart:io';
import 'package:http/io_client.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.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:signalr_core/signalr_core.dart';
abstract class ChatRepo {
Future<HubConnection> getHubConnection();
Future<void> markMessageAsRead({required int messageId});
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int requestOfferId, int pageIndex = 0, int pageSize = 0});
}
class ChatRepoImp implements ChatRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<HubConnection> getHubConnection() async {
final userId = AppState().getUser.data!.userInfo!.userId ?? "";
@ -18,15 +31,49 @@ class ChatRepoImp implements ChatRepo {
HubConnection hub;
hub = HubConnectionBuilder()
.withUrl(
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()
..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
print(message);
},
))
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
log(message);
},
))
.build();
return hub;
}
@override
Future<void> markMessageAsRead({required int messageId}) async {
var queryParameters = {
"id": messageId.toString(),
};
await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.messageIsReadUpdate,
queryParameters,
token: appState.getUser.data!.accessToken,
);
}
@override
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int requestOfferId, int pageIndex = 0, int pageSize = 0}) async {
var queryParameters = {
"ReqOfferID": requestOfferId.toString(),
"ProviderID": providerId.toString(),
"PageSize": pageSize.toString(),
"PageIndex": pageIndex.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getChatMessages,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
List<ChatMessageModel> chatMessages = List.generate(
genericRespModel.data.length,
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
);
return chatMessages;
}
}

@ -2,16 +2,23 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class RequestRepo {
Future<GenericRespModel> createRequest(Map<String, dynamic> map);
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0});
Future<ProviderOffersModel> getOffersFromProvidersByRequest({required int requestId});
Future<List<RequestModel>> getRequests(Map<String, dynamic> postParams);
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId});
}
class RequestRepoImp implements RequestRepo {
@ -60,10 +67,44 @@ class RequestRepoImp implements RequestRepo {
);
List<OffersModel> offersList = List.generate(
genericRespModel.data.length,
(index) => OffersModel.fromJson(
genericRespModel.data[index],
),
(index) => OffersModel.fromJson(genericRespModel.data[index]),
);
return offersList;
}
@override
Future<ProviderOffersModel> getOffersFromProvidersByRequest({required int requestId}) async {
final customerId = appState.getUser.data!.userInfo!.customerId;
var queryParameters = {
"customerID": customerId.toString(),
"requestID": requestId.toString(),
};
GenericRespModel genericRespModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.requestOffersSpsGet,
queryParameters,
token: appState.getUser.data!.accessToken,
);
ProviderOffersModel providerOffersModel = ProviderOffersModel();
if (genericRespModel.data != null && genericRespModel.data.length > 0) {
providerOffersModel = ProviderOffersModel.fromJson(genericRespModel.data.first);
}
return providerOffersModel;
}
@override
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId}) async {
var queryParameters = {
"requestOfferId": requestOfferId.toString(),
"offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(),
};
GenericRespModel genericRespModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.updateRequestOffer,
queryParameters,
token: appState.getUser.data!.accessToken,
);
return genericRespModel;
}
}

@ -250,14 +250,18 @@ class Utils {
}
}
static statusContainerChip({required String text, EdgeInsetsGeometry padding = const EdgeInsets.symmetric(vertical: 3, horizontal: 6), Color chipColor = MyColors.greenColor}) {
static statusContainerChip(
{required String text, EdgeInsetsGeometry padding = const EdgeInsets.symmetric(vertical: 3, horizontal: 6), Color chipColor = MyColors.greenColor, Color textColor = MyColors.white}) {
return Container(
decoration: BoxDecoration(
color: chipColor,
borderRadius: const BorderRadius.all(Radius.circular(200)),
),
padding: padding,
child: text.toText(fontSize: 10, color: MyColors.white));
child: text.toText(
fontSize: 10,
color: textColor,
));
}
static InputDecoration txtField(String label) {

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/utils/enums.dart';
import '../utils/enums.dart';
class BaseVM extends ChangeNotifier {
ViewState _state = ViewState.idle;

@ -1,22 +1,31 @@
// 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/cat_message_model.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});
ChatVM({required this.chatRepo, required this.requestRepo});
late HubConnection hubConnection;
List<ChatMessageModel> chatMessages = [];
String chatMessageText = "";
updateChatMessageText(String value) {
@ -28,12 +37,85 @@ class ChatVM extends ChangeNotifier {
notifyListeners();
}
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages}) async {
chatMessages.addAll(messages);
List<OfferRequestCommentModel> 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<void> onNewMessageReceived({required List<ChatMessageModel> messages, required BuildContext context}) async {
if (AppState().currentAppType == AppType.customer) {
for (var msg in messages) {
log("printing senderUserID: ${msg.senderUserID}");
log("printing providerUserId: ${serviceProviderOffersList.first.providerUserId}");
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID);
if (providerIndex != -1) {
serviceProviderOffersList[providerIndex].chatMessages!.add(msg);
}
}
} else {
for (var msg in messages) {
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerID == msg.senderUserID);
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: msg, index: providerIndex);
}
}
}
notifyListeners();
}
Future<void> buildHubConnection() async {
Future<void> buildHubConnection(BuildContext context) async {
// if (hubConnection.state != HubConnectionState.Connected) {
try {
hubConnection = await chatRepo.getHubConnection();
@ -45,7 +127,7 @@ class ChatVM extends ChangeNotifier {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceived(messages: chat);
onNewMessageReceived(messages: chat, context: context);
logger.i("I received ping : ${arguments.toString()}");
});
} catch (e) {
@ -62,9 +144,10 @@ class ChatVM extends ChangeNotifier {
required String message,
required int requestId,
required String offerPrice,
required BuildContext context,
}) async {
if (hubConnection.state != HubConnectionState.connected) {
await buildHubConnection();
await buildHubConnection(context);
}
if (hubConnection.state == HubConnectionState.connected) {
final providerId = AppState().getUser.data!.userInfo!.providerId;
@ -74,10 +157,10 @@ class ChatVM extends ChangeNotifier {
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"Message": message,
"ChatText": message,
"RequestID": requestId,
"RequestOfferID": 0,
"RequestOffer": <String, dynamic>{
"ReqOfferID": 0,
"ReqOffer": <String, dynamic>{
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": providerId,
@ -101,23 +184,29 @@ class ChatVM extends ChangeNotifier {
required String message,
required int requestId,
required String offerPrice,
required BuildContext context,
}) async {
if (message.isEmpty) return false;
if (hubConnection.state != HubConnectionState.connected) {
await buildHubConnection();
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("here the sender: $userId");
log("here the receiver: $receiverId");
hubConnection.invoke(
"SendMessageRequestOffer",
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"Message": message,
"ChatText": message,
"RequestID": requestId,
"ReqOfferID": 0,
}
],
).catchError((e) {
@ -127,15 +216,83 @@ class ChatVM extends ChangeNotifier {
});
ChatMessageModel chatMessageModel = ChatMessageModel(
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
message: message,
chatText: message,
isMyMessage: true,
requestID: requestId,
senderName: name,
senderUserID: userId,
);
onNewMessageReceived(messages: [chatMessageModel]);
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.customerID == userId);
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
}
}
}
return true;
}
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 providerOfferIndex}) async {
try {
Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, requestOfferId: requestOfferId);
serviceProviderOffersList[providerOfferIndex].chatMessages = chatMessages;
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 providerId, required int requestOfferId, required int customerRequestIndex}) async {
try {
Utils.showLoading(context);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, requestOfferId: requestOfferId);
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex);
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}) 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;
}
}
}

@ -9,7 +9,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/chat_models/cat_message_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
@ -87,6 +87,17 @@ class RequestsVM extends BaseVM {
notifyListeners();
}
addChatMessagesInRequestsModel({required ChatMessageModel msg, required int index}) {
myFilteredRequests[index].chatMessages.add(msg);
notifyListeners();
}
overwriteChatMessagesInRequestsModel({required List<ChatMessageModel> messages, required int index}) {
myFilteredRequests[index].chatMessages.clear();
myFilteredRequests[index].chatMessages = messages;
notifyListeners();
}
applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) {
if (requestsTypeFilterOptions.isEmpty) return;
for (var value in requestsTypeFilterOptions) {
@ -397,15 +408,18 @@ class RequestsVM extends BaseVM {
required int requestId,
required String offerPrice,
required RequestModel requestModel,
required int requestIndex,
}) async {
if (isSendOfferValidated()) {
bool status = await context.read<ChatVM>().onSendMessageForRequestOffer(
receiverId: receiverId,
chatMessageType: ChatMessageTypeEnum.offer,
message: message,
requestId: requestId,
offerPrice: offerPrice,
);
final chatVM = context.read<ChatVM>();
bool status = await chatVM.onSendMessageForRequestOffer(
receiverId: receiverId,
chatMessageType: ChatMessageTypeEnum.offer,
message: message,
requestId: requestId,
offerPrice: offerPrice,
context: context,
);
if (status) {
final senderName = AppState().getUser.data!.userInfo!.firstName;
@ -414,17 +428,19 @@ class RequestsVM extends BaseVM {
Navigator.pop(context);
ChatMessageModel chatMessageModel = ChatMessageModel(
isMyMessage: true,
message: message,
chatText: message,
messageType: ChatMessageTypeEnum.freeText.getIdFromChatMessageTypeEnum(),
senderName: senderName,
senderUserID: senderId,
);
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel]);
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel], context: context);
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestModel: requestModel,
requestId: requestModel.id,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
requestIndex: requestIndex,
providerIndex: -1,
);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}

@ -1,14 +1,20 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/chat_models/cat_message_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
@ -22,91 +28,142 @@ class ChatView extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: "Chat"),
body: Consumer<ChatVM>(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return Column(
children: [
Expanded(
child: ListView.separated(
itemCount: chatVM.chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatVM.chatMessages[index];
return ChatMessageCustomWidget(
isSent: chatMessageModel.isMyMessage ?? false,
profileUrl: MyAssets.bnCar,
messageText: "${chatMessageModel.message}",
messageTypeEnum: chatMessageModel.messageTypeEnum ?? ChatMessageTypeEnum.freeText,
requestOfferStatusEnum:
(chatMessageModel.requestOffer != null ? chatMessageModel.requestOffer!.requestOfferStatusEnum : RequestOfferStatusEnum.offer) ?? RequestOfferStatusEnum.offer,
senderName: "${chatMessageModel.senderName}",
);
}).horPaddingMain(),
),
10.width,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 7,
child: TxtField(
value: chatVM.chatMessageText,
hint: "Type your message here..",
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
final chatMessages = AppState().currentAppType == AppType.customer
? chatVM.serviceProviderOffersList[chatViewArguments.providerIndex].chatMessages
: requestVM.myFilteredRequests[chatViewArguments.requestIndex].chatMessages;
return chatMessages == null
? Center(child: "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor))
: Column(
children: [
Expanded(
child: ListView.separated(
itemCount: chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatMessages[index];
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel);
}).horPaddingMain(),
),
),
Expanded(
flex: 1,
child: const Icon(
Icons.send_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
final status = await chatVM.onTextMessageSend(
receiverId: chatViewArguments.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArguments.chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArguments.requestModel!.id : 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
10.width,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 7,
child: TxtField(
value: chatVM.chatMessageText,
hint: "Type your message here..",
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
),
),
Expanded(
flex: 1,
child: const Icon(
Icons.send_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
final status = await chatVM.onTextMessageSend(
context: context,
receiverId: chatViewArguments.receiverId,
message: chatVM.chatMessageText,
requestId: chatViewArguments.chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArguments.requestId ?? 0 : 0,
offerPrice: "0.0",
chatMessageType: ChatMessageTypeEnum.freeText,
);
if (status) {
chatVM.clearChatMessageText();
}
},
),
)
],
).toContainer(isShadowEnabled: true),
],
);
if (status) {
chatVM.clearChatMessageText();
}
},
),
)
],
).toContainer(isShadowEnabled: true),
],
);
}),
// body:
);
}
}
class ChatMessageCustomWidget extends StatelessWidget {
final String profileUrl;
final String senderName;
final String messageText;
final ChatMessageTypeEnum messageTypeEnum;
final RequestOfferStatusEnum requestOfferStatusEnum;
final bool isSent;
class ChatMessageCustomWidget extends StatefulWidget {
final ChatMessageModel chatMessageModel;
const ChatMessageCustomWidget({super.key, required this.chatMessageModel});
const ChatMessageCustomWidget({
super.key,
required this.profileUrl,
required this.senderName,
required this.messageText,
required this.messageTypeEnum,
this.requestOfferStatusEnum = RequestOfferStatusEnum.offer,
required this.isSent,
});
@override
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
}
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Future buildRejectOfferBottomSheet() {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return InfoBottomSheet(
title: "Make an offer".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
ListView.separated(
shrinkWrap: true,
itemCount: chatVM.offerRejectModelList.length,
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 0.5),
itemBuilder: (BuildContext context, int index) {
OfferRequestCommentModel offerRequestCommentModel = chatVM.offerRejectModelList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
chatVM.updateSelectionInOfferRejectModelList(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
12.height,
TxtField(
maxLines: 5,
value: chatVM.rejectOfferDescription,
errorValue: chatVM.rejectOfferDescriptionError,
keyboardType: TextInputType.text,
hint: "Description",
onChanged: (v) => chatVM.updateRejectOfferDescription(v),
),
],
),
25.height,
ShowFillButton(
title: "Submit",
onPressed: () {},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
Widget buildOfferDetailsInChatMessage({required RequestOfferStatusEnum requestOfferStatusEnum}) {
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) {
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer:
return Column(
@ -115,7 +172,7 @@ class ChatMessageCustomWidget extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"40000".toText(fontSize: 19, isBold: true),
chatMessageModel.reqOffer!.price.toString().toText(fontSize: 19, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
@ -130,7 +187,22 @@ class ChatMessageCustomWidget extends StatelessWidget {
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () {},
onPressed: () async {
log("message: ${chatMessageModel.reqOfferID}");
int status = await context.read<ChatVM>().onActionOfferTapped(
context: context,
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
reqOfferId: chatMessageModel.reqOfferID ?? -1,
);
if (status != -1) {
log("accepted: $status");
if (chatMessageModel.reqOfferID == status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
setState(() {});
}
}
},
backgroundColor: MyColors.white,
txtColor: MyColors.greenColor,
),
@ -142,10 +214,22 @@ class ChatMessageCustomWidget extends StatelessWidget {
title: "Reject",
borderColor: MyColors.redColor,
isFilled: false,
onPressed: () {},
backgroundColor: MyColors.white,
txtColor: MyColors.redColor,
fontSize: 9,
onPressed: () async {
buildRejectOfferBottomSheet();
// int status =
// await context.read<ChatVM>().onActionOfferTapped(context: context, requestOfferStatusEnum: RequestOfferStatusEnum.rejected, reqOfferId: chatMessageModel.reqOfferID ?? -1);
//
// if (status != -1) {
// log("rejected: $status");
// if (chatMessageModel.reqOfferID == status) {
// chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.rejected;
// setState(() {});
// }
// }
},
),
)
],
@ -206,14 +290,14 @@ class ChatMessageCustomWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: isSent ? TextDirection.rtl : TextDirection.ltr,
textDirection: (widget.chatMessageModel.isMyMessage ?? false) ? TextDirection.rtl : TextDirection.ltr,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Image.asset(
profileUrl,
MyAssets.bnCar,
width: 34,
height: 34,
fit: BoxFit.fill,
@ -228,7 +312,7 @@ class ChatMessageCustomWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(isSent ? "You" : senderName).toText(fontSize: 16, isBold: true),
((widget.chatMessageModel.isMyMessage ?? false) ? "You" : widget.chatMessageModel.senderName ?? "").toText(fontSize: 16, isBold: true),
],
),
5.height,
@ -238,23 +322,23 @@ class ChatMessageCustomWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: messageText.toText(
color: isSent ? MyColors.white : MyColors.lightTextColor,
child: (widget.chatMessageModel.chatText ?? "").toText(
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
fontSize: 12,
// isBold: true,
),
),
],
),
if (messageTypeEnum == ChatMessageTypeEnum.offer) ...[
buildOfferDetailsInChatMessage(requestOfferStatusEnum: requestOfferStatusEnum),
if (widget.chatMessageModel.chatMessageTypeEnum == ChatMessageTypeEnum.offer) ...[
buildOfferDetailsInChatMessage(chatMessageModel: widget.chatMessageModel, context: context),
],
],
).toContainer(
isShadowEnabled: !isSent,
backgroundColor: isSent ? MyColors.darkIconColor : MyColors.white,
isShadowEnabled: !(widget.chatMessageModel.isMyMessage ?? false),
backgroundColor: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.darkIconColor : MyColors.white,
borderRadius: 0,
margin: EdgeInsets.fromLTRB(isSent ? 25 : 0, 0, !isSent ? 25 : 0, 0),
margin: EdgeInsets.fromLTRB((widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0, !(widget.chatMessageModel.isMyMessage ?? false) ? 25 : 0, 0),
),
],
),

@ -1,16 +1,16 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class OfferListPage extends StatelessWidget {
final OfferListPageArguments offerListPageArguments;
@ -19,76 +19,78 @@ class OfferListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final List<OffersModel> offersList = offerListPageArguments.offersList;
final List<ServiceProvidersOffers> serviceProviderOffers = offerListPageArguments.serviceProviderOffers;
return Scaffold(
appBar: const CustomAppBar(title: "Offers"),
body: offersList.isEmpty
body: serviceProviderOffers.isEmpty
? Center(child: "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: offersList.length,
itemCount: serviceProviderOffers.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
OffersModel offersModel = offersList[index];
return Stack(
alignment: Alignment.bottomRight,
ServiceProvidersOffers offersModel = serviceProviderOffers[index];
return Column(
children: [
Column(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(offersModel.serviceProvider!.companyName ?? "").toText(fontSize: 16, isBold: true),
//Un read offers count
// Center(
// child: "2".toText(
// color: Colors.white,
// isBold: true,
// fontSize: 10,
// ),
// ).toContainer(
// backgroundColor: MyColors.redColor,
// borderRadius: 100,
// paddingAll: 1,
// width: 20,
// height: 20,
// ),
],
(offersModel.name ?? "").toText(fontSize: 16, isBold: true),
Center(
child: "${offersModel.offerCount}".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 20,
height: 20,
),
8.height,
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: "${offersModel.comment} and This is dummy text edition.".toText(
color: MyColors.lightTextColor,
fontSize: 12,
),
"${offersModel.companyName}".toText(
color: MyColors.lightTextColor,
fontSize: 12,
),
12.width,
"9 Hours Ago".toText(
" | 1 hour ago".toText(
color: MyColors.lightTextColor,
)
fontSize: 12,
),
],
),
const Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
),
const Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
).onPress(() {
log("here: ${offersModel.serviceProvider!.providerGUID}");
).onPress(() async {
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.serviceProvider!.providerGUID}",
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
requestModel: offerListPageArguments.requestModel);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.providerUserId}",
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
requestId: offerListPageArguments.requestId,
providerIndex: index,
requestIndex: -1, // This will be only send in case of provider
);
final chatVM = context.read<ChatVM>();
await chatVM.getUsersChatMessagesForCustomer(context: context, providerId: offersModel.providerId ?? 0, requestOfferId: 0, providerOfferIndex: index).whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,

@ -1,12 +1,13 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:developer';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
@ -17,8 +18,9 @@ import 'package:provider/provider.dart';
class RequestItem extends StatelessWidget {
final RequestModel request;
final AppType appType;
final int requestIndex;
const RequestItem({super.key, required this.request, required this.appType});
const RequestItem({super.key, required this.request, required this.appType, required this.requestIndex});
@override
Widget build(BuildContext context) {
@ -80,19 +82,19 @@ class RequestItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
request.price.toString().toText(
fontSize: 20,
color: Colors.black,
isBold: true,
),
fontSize: 20,
color: Colors.black,
isBold: true,
),
2.width,
"SAR"
.toText(
color: MyColors.lightTextColor,
fontSize: 10,
)
color: MyColors.lightTextColor,
fontSize: 10,
)
.paddingOnly(
bottom: 3,
),
bottom: 3,
),
],
),
const Icon(
@ -105,10 +107,12 @@ class RequestItem extends StatelessWidget {
],
).toContainer(isShadowEnabled: true).onPress(() async {
if (appType == AppType.provider) {
navigateWithName(context, AppRoutes.requestsDetailPage, arguments: request);
RequestDetailPageArguments requestDetailPageArguments = RequestDetailPageArguments(requestIndex: requestIndex, requestModel: request);
navigateWithName(context, AppRoutes.requestsDetailPage, arguments: requestDetailPageArguments);
} else {
List<OffersModel> offers = await context.read<RequestsVM>().getOffersByRequest(requestId: request.id, context: context);
OfferListPageArguments offerListPageArguments = OfferListPageArguments(offersList: offers, requestModel: request);
ChatVM chatVM = context.read<ChatVM>();
await chatVM.getOffersFromProvidersByRequest(requestId: request.id, context: context);
OfferListPageArguments offerListPageArguments = OfferListPageArguments(serviceProviderOffers: chatVM.serviceProviderOffersList, requestId: request.id);
navigateWithName(context, AppRoutes.offersListPage, arguments: offerListPageArguments);
}
});

@ -44,8 +44,8 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
void initState() {
super.initState();
if (AppState().currentAppType == AppType.provider) {
phoneNum = "966580816976";
password = "123@Shf";
phoneNum = "966598646795";
password = "Zahoor@123";
}
scheduleMicrotask(() {
userVM = Provider.of(context, listen: false);

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class CheckBoxWithTitleDescription extends StatelessWidget {
final bool isSelected;
@ -38,3 +40,49 @@ class CheckBoxWithTitleDescription extends StatelessWidget {
);
}
}
class CircleCheckBoxWithTitle extends StatelessWidget {
final bool isChecked;
final String title;
final Function() onSelected;
final Color selectedColor;
const CircleCheckBoxWithTitle({super.key, required this.title, required this.isChecked, required this.onSelected, required this.selectedColor});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 20,
width: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isChecked ? selectedColor : Colors.transparent,
border: Border.all(
color: isChecked ? Colors.transparent : MyColors.darkTextColor,
),
),
child: const Center(child: Icon(Icons.check_rounded, size: 16, color: MyColors.white)),
),
5.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
title.toText(fontSize: 14, isBold: false),
],
),
),
],
).onPress((){
onSelected();
}),
);
}
}

Loading…
Cancel
Save