Chat Implementation 1.0

mirza_development
Faiz Hashmi 2 years ago
parent a76b8d8244
commit 01d9ad68a2

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -260,6 +260,10 @@ class MyAssets {
static String tamaraArPng = "${assetPath}icons/payments/tamara_ar.png";
static String tamaraEngPng = "${assetPath}icons/payments/tamara_en.png";
static String visaPng = "${assetPath}icons/payments/visa.png";
static String whatsAppIcon = "${assetPath}icons/whatsapp_icon.svg";
}
RegExp numReg = RegExp(r".*[0-9].*");

@ -117,12 +117,19 @@ class ChatViewArguments {
final String receiverId;
final int providerIndex;
final int requestIndex;
ChatViewArguments({required this.chatTypeEnum, this.requestId, required this.senderId, required this.receiverId, required this.providerIndex, required this.requestIndex});
final RequestModel? requestModel;
ChatViewArguments({
required this.chatTypeEnum,
this.requestId,
required this.senderId,
required this.receiverId,
required this.providerIndex,
required this.requestIndex,
this.requestModel,
});
}
class OfferListPageArguments {
final List<ServiceProvidersOffers> serviceProviderOffers;
final int? requestId;

@ -28,6 +28,7 @@ extension EmailValidator on String {
decoration: isUnderLine
? TextDecoration.underline
: textDecoration ?? TextDecoration.none,
fontSize: fontSize ?? 10,
fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.w600,
color: color ?? MyColors.darkTextColor,

@ -1,3 +1,5 @@
import 'dart:developer';
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';
@ -35,8 +37,13 @@ class ChatMessageModel {
this.isMyMessage,
});
@override
String toString() {
return 'ChatMessageModel{id: $id, senderUserID: $senderUserID, senderName: $senderName, messageType: $messageType, chatMessageTypeEnum: $chatMessageTypeEnum, chatText: $chatText, requestID: $requestID, reqOfferID: $reqOfferID, serviceProviderID: $serviceProviderID, offerStatus: $offerStatus, reqOffer: $reqOffer, isRead: $isRead, readOn: $readOn, isMyMessage: $isMyMessage}';
}
ChatMessageModel.fromJson(Map<String, dynamic> json) {
final myUserId = AppState().getUser.data!.userInfo!.userId.toString();
final myUserId = AppState().getUser.data!.userInfo!.userId.toString().toUpperCase();
id = json['id'];
senderUserID = json['senderUserID'];
senderName = json['senderName'];
@ -50,7 +57,8 @@ class ChatMessageModel {
reqOffer = json['reqOffer'] != null ? ReqOffer.fromJson(json['reqOffer']) : null;
isRead = json['isRead'];
readOn = json['readOn'];
isMyMessage = (json['senderUserId']).toString() == myUserId;
isMyMessage = (json['senderUserID']).toString().toUpperCase()== myUserId;
}
}
@ -76,6 +84,7 @@ class ReqOffer {
});
ReqOffer.fromJson(Map<String, dynamic> json) {
log("the json: $json");
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];

@ -65,7 +65,7 @@ class ServiceProvidersOffers {
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'];
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'];

@ -16,6 +16,8 @@ class RequestModel {
int offerCount;
int id;
int customerId;
bool isChatted;
String customerUserID;
dynamic customer;
String brand;
String model;
@ -51,6 +53,8 @@ class RequestModel {
required this.offerCount,
required this.id,
required this.customerId,
required this.isChatted,
required this.customerUserID,
required this.customer,
required this.brand,
required this.model,
@ -88,6 +92,8 @@ class RequestModel {
offerCount: json["offerCount"],
id: json["id"],
customerId: json["customerID"],
isChatted: json["isChatted"],
customerUserID: json["customerUserID"],
customer: json["customer"],
brand: json["brand"],
model: json["model"],

@ -15,7 +15,7 @@ abstract class ChatRepo {
Future<void> markMessageAsRead({required int messageId});
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int requestOfferId, int pageIndex = 0, int pageSize = 0});
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int customerId, required int requestOfferId, required int requestId, int pageIndex = 0, int pageSize = 0});
}
class ChatRepoImp implements ChatRepo {
@ -31,13 +31,14 @@ class ChatRepoImp implements ChatRepo {
HubConnection hub;
hub = HubConnectionBuilder()
.withUrl(
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
log(message);
},
))
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()
..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
log(message);
},
))
.build();
return hub;
}
@ -48,7 +49,7 @@ class ChatRepoImp implements ChatRepo {
"id": messageId.toString(),
};
await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
(json) => GenericRespModel.fromJson(json),
ApiConsts.messageIsReadUpdate,
queryParameters,
token: appState.getUser.data!.accessToken,
@ -56,24 +57,29 @@ class ChatRepoImp implements ChatRepo {
}
@override
Future<List<ChatMessageModel>> getUsersChatMessages({required int providerId, required int requestOfferId, int pageIndex = 0, int pageSize = 0}) async {
Future<List<ChatMessageModel>> getUsersChatMessages(
{required int providerId, required int customerId, required int requestOfferId, required int requestId, int pageIndex = 0, int pageSize = 0}) async {
var queryParameters = {
"ReqOfferID": requestOfferId.toString(),
"RequestID": requestId.toString(),
"ProviderID": providerId.toString(),
"CustomerID": customerId.toString(),
"PageSize": pageSize.toString(),
"PageIndex": pageIndex.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
(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;
if (genericRespModel.messageStatus == 1 && genericRespModel.data != null) {
List<ChatMessageModel> chatMessages = List.generate(
genericRespModel.data.length,
(index) => ChatMessageModel.fromJson(genericRespModel.data[index]),
);
return chatMessages;
}
return [];
}
}

@ -39,10 +39,7 @@ class AppointmentsVM extends BaseVM {
final ProviderRepo providerRepo;
final AppointmentRepo scheduleRepo;
AppointmentsVM({required this.commonServices,
required this.scheduleRepo,
required this.providerRepo,
required this.commonRepo});
AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false;
int selectedBranch = 0;
@ -68,8 +65,7 @@ class AppointmentsVM extends BaseVM {
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
bool ifItemAlreadySelected(int id) {
int indexFound = allSelectedItemsInAppointments
.indexWhere((element) => element.id == id);
int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
if (indexFound != -1) {
return true;
}
@ -80,22 +76,16 @@ class AppointmentsVM extends BaseVM {
setupProviderAppointmentFilter() {
appointmentsFilterOptions.clear();
appointmentsFilterOptions.add(
FilterListModel(id: 0, title: "All Appointments", isSelected: true));
appointmentsFilterOptions
.add(FilterListModel(id: 6, title: "Upcoming", isSelected: false));
appointmentsFilterOptions
.add(FilterListModel(id: 3, title: "Arrived", isSelected: false));
appointmentsFilterOptions
.add(FilterListModel(id: 7, title: "In Progress", isSelected: false));
appointmentsFilterOptions
.add(FilterListModel(id: 8, title: "Completed", isSelected: false));
appointmentsFilterOptions.add(FilterListModel(id: 0, title: "All Appointments", isSelected: true));
appointmentsFilterOptions.add(FilterListModel(id: 6, title: "Upcoming", isSelected: false));
appointmentsFilterOptions.add(FilterListModel(id: 3, title: "Arrived", isSelected: false));
appointmentsFilterOptions.add(FilterListModel(id: 7, title: "In Progress", isSelected: false));
appointmentsFilterOptions.add(FilterListModel(id: 8, title: "Completed", isSelected: false));
}
Future<void> onItemsSelectedInService() async {
if (currentServiceSelection != null) {
int index = servicesInCurrentAppointment.indexWhere((element) =>
element.serviceId == currentServiceSelection!.serviceId!);
int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
if (index == -1) {
double totalPrice = 0.0;
@ -116,14 +106,12 @@ class AppointmentsVM extends BaseVM {
bool isSuccess = false;
List<int> appointmentIdsList = [];
try {
GenericRespModel genericRespModel =
await scheduleRepo.createServiceAppointment(
GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment(
schedules: serviceAppointmentScheduleList,
serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
);
if (genericRespModel.messageStatus == 2 ||
genericRespModel.data == null) {
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
@ -141,17 +129,13 @@ class AppointmentsVM extends BaseVM {
}
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(
appointmentStatusEnum: AppointmentStatusEnum.booked);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
Utils.hideLoading(context);
resetAfterBookingAppointment();
if (isSuccess) {
if (amountToPayForAppointment > 0) {
context
.read<PaymentVM>()
.updateAppointmentIdsForPayment(ids: appointmentIdsList);
navigateWithName(context, AppRoutes.paymentMethodsView,
arguments: PaymentTypes.appointment);
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: appointmentIdsList);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
} else {
Utils.showToast("Your appointment has been booked successfully!");
getMyAppointments();
@ -163,36 +147,28 @@ class AppointmentsVM extends BaseVM {
}
}
Future<void> onConfirmAppointmentPressed(
{required BuildContext context, required appointmentId}) async {
context
.read<PaymentVM>()
.updateAppointmentIdsForPayment(ids: [appointmentId]);
navigateWithName(context, AppRoutes.paymentMethodsView,
arguments: PaymentTypes.appointment);
Future<void> onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async {
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: [appointmentId]);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
}
Future<void> onCancelAppointmentPressed({required BuildContext context,
required AppointmentListModel appointmentListModel}) async {
Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel =
await scheduleRepo.cancelOrRescheduleServiceAppointment(
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
serviceAppointmentID: appointmentListModel.id ?? 0,
serviceSlotID: appointmentListModel.serviceSlotID ?? 0,
appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel
);
if (genericRespModel.messageStatus == 2 ||
genericRespModel.data == null) {
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data == 1) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(
appointmentStatusEnum: AppointmentStatusEnum.cancelled);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast("${genericRespModel.message.toString()}");
await getMyAppointments();
Utils.hideLoading(context);
@ -223,8 +199,7 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
SelectionModel branchSelectedCategoryId =
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateProviderCategoryId(SelectionModel id) {
branchSelectedCategoryId = id;
@ -243,30 +218,23 @@ class AppointmentsVM extends BaseVM {
void updateBranchServiceId(SelectionModel id) async {
branchSelectedServiceId = id;
currentServiceSelection = branchServices.firstWhere(
(element) => element.serviceProviderServiceId == id.selectedId);
currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
notifyListeners();
}
void removeServiceInCurrentAppointment(int index) {
int serviceId = servicesInCurrentAppointment
.elementAt(index)
.serviceProviderServiceId ??
-1;
allSelectedItemsInAppointments.removeWhere(
(element) => element.serviceProviderServiceId == serviceId);
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
servicesInCurrentAppointment.removeAt(index);
notifyListeners();
}
resetCategorySelectionBottomSheet() {
selectedSubServicesCounter = 0;
branchSelectedCategoryId =
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false;
branchSelectedServiceId =
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
currentServiceSelection = null;
}
@ -281,32 +249,24 @@ class AppointmentsVM extends BaseVM {
populateAppointmentsFilterList() async {
appointmentsFilterOptions.clear();
myAppointmentsEnum = await commonRepo.getEnumTypeValues(
enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums
myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums
for (int i = 0; i < myAppointmentsEnum.length; i++) {
appointmentsFilterOptions.add(FilterListModel(
title: myAppointmentsEnum[i].enumValueStr,
isSelected: false,
id: myAppointmentsEnum[i].enumValue));
appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue));
}
appointmentsFilterOptions.insert(
0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
notifyListeners();
}
applyFilterOnAppointmentsVM(
{required AppointmentStatusEnum appointmentStatusEnum,
bool isNeedCustomerFilter = false}) {
applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum, bool isNeedCustomerFilter = false}) {
if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
appointmentsFilterOptions.forEach((element) {
if (element.id ==
appointmentStatusEnum.getIdFromAppointmentStatusEnum()) {
if (element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum()) {
element.isSelected = true;
}
});
@ -321,11 +281,7 @@ class AppointmentsVM extends BaseVM {
return;
}
myFilteredAppointments = myAppointments
.where((element) =>
element.appointmentStatusID! ==
appointmentStatusEnum.getIdFromAppointmentStatusEnum())
.toList();
myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers();
notifyListeners();
}
@ -341,9 +297,7 @@ class AppointmentsVM extends BaseVM {
// Create a list of CustomerData instances
myFilteredAppointments2 = uniqueCustomerIDs.map((id) {
List<AppointmentListModel> list = myFilteredAppointments
.where((item) => item.customerID == id)
.toList();
List<AppointmentListModel> list = myFilteredAppointments.where((item) => item.customerID == id).toList();
AppointmentListModel model = list.first;
model.customerAppointmentList = list;
return model;
@ -368,10 +322,7 @@ class AppointmentsVM extends BaseVM {
myAppointments = await commonRepo.getMyAppointments();
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments
.where((element) =>
element.appointmentStatusEnum == AppointmentStatusEnum.booked)
.toList();
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
setState(ViewState.idle);
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
notifyListeners();
@ -379,9 +330,7 @@ class AppointmentsVM extends BaseVM {
AppointmentSlots? appointmentSlots;
Future<void> getAppointmentSlotsInfo({required Map<String, dynamic> map,
required BuildContext context,
bool isNeedToRebuild = false}) async {
Future<void> getAppointmentSlotsInfo({required Map<String, dynamic> map, required BuildContext context, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
try {
MResponse genericRespModel = await scheduleRepo.getAppointmentSlots(map);
@ -395,8 +344,7 @@ class AppointmentsVM extends BaseVM {
}
}
Future<void> getProviderMyAppointments(Map<String, dynamic> map,
{bool isNeedToRebuild = false}) async {
Future<void> getProviderMyAppointments(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
myAppointments = await scheduleRepo.getMyAppointments(map);
@ -406,9 +354,7 @@ class AppointmentsVM extends BaseVM {
// element.appointmentStatusEnum == AppointmentStatusEnum.booked)
// .toList();
setState(ViewState.idle);
applyFilterOnAppointmentsVM(
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
notifyListeners();
}
@ -418,10 +364,10 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
updateAppointmentStatus(Map<String, dynamic> map,{bool isNeedToRebuild = false}) async {
updateAppointmentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
try {
MResponse genericRespModel = await scheduleRepo.updateAppointmentStatus(map);
MResponse genericRespModel = await scheduleRepo.updateAppointmentStatus(map);
if (genericRespModel.messageStatus == 1) {
Utils.showToast("appointment status updated");
@ -433,10 +379,10 @@ class AppointmentsVM extends BaseVM {
}
}
updateAppointmentPaymentStatus(Map<String, dynamic> map,{bool isNeedToRebuild = false}) async {
updateAppointmentPaymentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
try {
MResponse genericRespModel = await scheduleRepo.updateAppointmentPaymentStatus(map);
MResponse genericRespModel = await scheduleRepo.updateAppointmentPaymentStatus(map);
if (genericRespModel.messageStatus == 1) {
Utils.showToast("payment status updated");
@ -448,55 +394,32 @@ class AppointmentsVM extends BaseVM {
}
}
updateSelectedAppointmentDate(
{required int dateIndex, required int scheduleIndex}) {
for (var element in serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList!) {
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
element.date!.isSelected = false;
}
serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList![dateIndex]
.date!
.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
final date = TimeSlotModel(
date: serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList![dateIndex]
.date!
.date,
slotId: serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList![dateIndex]
.date!
.slotId,
date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
isSelected: true,
slot: "",
);
serviceAppointmentScheduleList[scheduleIndex]
.selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
notifyListeners();
}
updateSelectedAppointmentSlotByDate(
{required int scheduleIndex, required int slotIndex}) {
for (var element in serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList!) {
updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
for (var element in element.availableSlots!) {
element.isSelected = false;
}
}
int index =
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList![index]
.availableSlots![slotIndex]
.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex]
.selectedCustomTimeDateSlotModel!
.availableSlots =
serviceAppointmentScheduleList[scheduleIndex]
.customTimeDateSlotList![index]
.availableSlots!;
int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
notifyListeners();
}
@ -510,9 +433,7 @@ class AppointmentsVM extends BaseVM {
int selectedSubServicesCounter = 0;
onItemUpdateOrSelected(int index, bool selected, int itemId) {
int serviceIndex = servicesInCurrentAppointment.indexWhere(
(element) =>
element.serviceId == currentServiceSelection!.serviceId!);
int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
// print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}");
// if (serviceIndex == -1) {
// return;
@ -527,28 +448,19 @@ class AppointmentsVM extends BaseVM {
allSelectedItemsInAppointments.add(serviceItemsFromApi[index]);
for (var element in allSelectedItemsInAppointments) {
if (!ifItemAlreadySelected(element.id!)) {
servicesInCurrentAppointment[serviceIndex]
.serviceItems!
.add(serviceItemsFromApi[index]);
servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]);
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
servicesInCurrentAppointment[serviceIndex]
.currentTotalServicePrice +
double.parse((serviceItemsFromApi[index].price) ?? "0.0");
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0");
}
}
}
if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1;
currentServiceSelection!.serviceItems!
.removeWhere((element) => element.id == itemId);
allSelectedItemsInAppointments
.removeWhere((element) => element.id == itemId);
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId);
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice -
double.parse((serviceItemsFromApi[index].price) ?? "0.0");
servicesInCurrentAppointment[serviceIndex]
.serviceItems!
.removeWhere((element) => element.id == itemId);
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0");
servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId);
}
notifyListeners();
}
@ -604,8 +516,7 @@ class AppointmentsVM extends BaseVM {
String pickHomeLocationError = "";
String selectSubServicesError = "";
SelectionModel branchSelectedServiceId =
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
bool isCategoryAlreadyPresent(int id) {
final contain = branchCategories.where((element) => element.id == id);
@ -618,16 +529,14 @@ class AppointmentsVM extends BaseVM {
void getBranchCategories() async {
for (var value in selectedBranchModel!.branchServices!) {
if (!isCategoryAlreadyPresent(value.categoryId!)) {
branchCategories
.add(DropValue(value.categoryId!, value.categoryName!, ""));
branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
}
}
notifyListeners();
}
getBranchServices({required int categoryId}) async {
branchSelectedServiceId =
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false;
pickedHomeLocation = "";
pickHomeLocationError = "";
@ -640,9 +549,7 @@ class AppointmentsVM extends BaseVM {
}
List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!
.where((element) => element.categoryId == categoryId)
.toList();
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
return filteredServices;
}
@ -684,8 +591,7 @@ class AppointmentsVM extends BaseVM {
return totalPrice.toString();
}
void openTheAddServiceBottomSheet(BuildContext context,
AppointmentsVM appointmentsVM) {
void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -696,8 +602,7 @@ class AppointmentsVM extends BaseVM {
);
}
void priceBreakDownClicked(BuildContext context,
ServiceModel selectedService) {
void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -713,27 +618,19 @@ class AppointmentsVM extends BaseVM {
Column(
children: List.generate(
selectedService.serviceItems!.length,
(index) =>
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}"
.toText(
fontSize: 12,
color: MyColors.lightTextColor,
isBold: true),
"${selectedService.serviceItems![index]
.price} SAR"
.toText(fontSize: 12, isBold: true),
],
),
(index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${selectedService.currentTotalServicePrice} SAR"
.toText(fontSize: 16, isBold: true),
"${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true),
],
),
if (selectedService.isHomeSelected) ...[
@ -742,20 +639,15 @@ class AppointmentsVM extends BaseVM {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${totalKms}km ".toText(
fontSize: 12,
color: MyColors.lightTextColor,
isBold: true),
"${selectedService.rangePricePerKm} x $totalKms"
.toText(fontSize: 12, isBold: true),
"${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR"
.toText(fontSize: 16, isBold: true),
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true),
],
),
],
@ -768,18 +660,11 @@ class AppointmentsVM extends BaseVM {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(selectedService.isHomeSelected
? "${(selectedService.currentTotalServicePrice) +
(double.parse((selectedService.rangePricePerKm ??
"0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true),
2.width,
"SAR"
.toText(
color: MyColors.lightTextColor,
fontSize: 16,
isBold: true)
.paddingOnly(bottom: 5),
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
@ -799,8 +684,7 @@ class AppointmentsVM extends BaseVM {
isValidated = false;
break;
}
if (schedule.selectedCustomTimeDateSlotModel!.date == null ||
!schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
isValidated = false;
break;
} else {
@ -808,9 +692,7 @@ class AppointmentsVM extends BaseVM {
isValidated = false;
break;
} else {
TimeSlotModel slot = schedule
.selectedCustomTimeDateSlotModel!.availableSlots!
.firstWhere((element) => element.isSelected);
TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
if (slot.date.isNotEmpty) {
isValidated = true;
break;
@ -819,8 +701,7 @@ class AppointmentsVM extends BaseVM {
}
}
if (!isValidated) {
Utils.showToast(
"You must select appointment time for each schedule's appointment.");
Utils.showToast("You must select appointment time for each schedule's appointment.");
return;
}
navigateWithName(context, AppRoutes.reviewAppointmentView);
@ -839,36 +720,30 @@ class AppointmentsVM extends BaseVM {
}
}
serviceAppointmentScheduleList =
await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIdsForHome: serviceItemIdsForHome,
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
);
if (serviceAppointmentScheduleList.isEmpty) {
Utils.hideLoading(context);
Utils.showToast(
"There are no available appointments for selected Items.");
Utils.showToast("There are no available appointments for selected Items.");
return;
}
totalAmount = 0.0;
amountToPayForAppointment = 0.0;
for (var schedule in serviceAppointmentScheduleList) {
amountToPayForAppointment =
amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
}
Utils.hideLoading(context);
navigateWithName(context, AppRoutes.bookAppointmenSchedulesView,
arguments: ScreenArgumentsForAppointmentDetailPage(
routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment
navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment
notifyListeners();
}
Future<void> onRescheduleAppointmentPressed({required BuildContext context,
required AppointmentListModel appointmentListModel}) async {
Future<void> onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context);
List<String> serviceItemIdsForHome = [];
@ -885,16 +760,14 @@ class AppointmentsVM extends BaseVM {
}
}
serviceAppointmentScheduleList =
await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIdsForHome: serviceItemIdsForHome,
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
);
if (serviceAppointmentScheduleList.isEmpty) {
Utils.hideLoading(context);
Utils.showToast(
"There are no available appointments for selected Items.");
Utils.showToast("There are no available appointments for selected Items.");
return;
}
Utils.hideLoading(context);
@ -902,36 +775,29 @@ class AppointmentsVM extends BaseVM {
navigateWithName(
context,
AppRoutes.bookAppointmenSchedulesView,
arguments: ScreenArgumentsForAppointmentDetailPage(
routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
); // 2 For Rescheduling an Appointment
notifyListeners();
}
Future<void> onRescheduleAppointmentConfirmPressed(
{required BuildContext context,
required int appointmentId,
required int selectedSlotId}) async {
Future<void> onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel =
await scheduleRepo.cancelOrRescheduleServiceAppointment(
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
serviceAppointmentID: appointmentId,
serviceSlotID: selectedSlotId,
appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel
);
if (genericRespModel.messageStatus == 2 ||
genericRespModel.data == null) {
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data == 1) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(
appointmentStatusEnum: AppointmentStatusEnum.cancelled);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast("${genericRespModel.message.toString()}");
getMyAppointments();
Utils.hideLoading(context);

@ -24,7 +24,7 @@ class ChatVM extends ChangeNotifier {
ChatVM({required this.chatRepo, required this.requestRepo});
late HubConnection hubConnection;
HubConnection? hubConnection;
String chatMessageText = "";
@ -105,7 +105,9 @@ class ChatVM extends ChangeNotifier {
}
} else {
for (var msg in messages) {
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerID == msg.senderUserID);
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerUserID == msg.senderUserID);
log("here is it: ${msg.senderUserID}");
log("here is it: ${context.read<RequestsVM>().myFilteredRequests.first.customerUserID.toString()}");
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: msg, index: providerIndex);
}
@ -116,26 +118,26 @@ class ChatVM extends ChangeNotifier {
}
Future<void> buildHubConnection(BuildContext context) async {
// if (hubConnection.state != HubConnectionState.Connected) {
try {
hubConnection = await chatRepo.getHubConnection();
await hubConnection.start();
hubConnection.on("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);
}
onNewMessageReceived(messages: chat, context: context);
logger.i("I received ping : ${arguments.toString()}");
});
} catch (e) {
logger.i("Error: ${e.toString()}");
}
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
try {
hubConnection = await chatRepo.getHubConnection();
await hubConnection!.start();
hubConnection!.on("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);
}
onNewMessageReceived(messages: chat, context: context);
logger.i("I received ping : ${arguments.toString()}");
});
} catch (e) {
logger.i("Error: ${e.toString()}");
}
notifyListeners();
// }
notifyListeners();
}
}
Future<bool> onSendMessageForRequestOffer({
@ -146,12 +148,12 @@ class ChatVM extends ChangeNotifier {
required String offerPrice,
required BuildContext context,
}) async {
if (hubConnection.state != HubConnectionState.connected) {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
await buildHubConnection(context);
}
if (hubConnection.state == HubConnectionState.connected) {
if (hubConnection!.state == HubConnectionState.connected) {
final providerId = AppState().getUser.data!.userInfo!.providerId;
hubConnection.invoke(
hubConnection!.invoke(
"SendMessageRequestOffer",
args: <Object>[
<String, dynamic>{
@ -188,21 +190,19 @@ class ChatVM extends ChangeNotifier {
}) async {
if (message.isEmpty) return false;
if (hubConnection.state != HubConnectionState.connected) {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
await buildHubConnection(context);
}
if (hubConnection.state == HubConnectionState.connected) {
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(
hubConnection!.invoke(
"SendMessageRequestOffer",
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"SenderUserID": userId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"ChatText": message,
"RequestID": requestId,
@ -229,13 +229,14 @@ class ChatVM extends ChangeNotifier {
serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel);
}
} else {
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerID == userId);
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => element.customerID == receiverId);
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
}
}
return true;
}
return true;
return false;
}
List<ServiceProvidersOffers> serviceProviderOffersList = [];
@ -255,10 +256,17 @@ class ChatVM extends ChangeNotifier {
}
}
Future<void> getUsersChatMessagesForCustomer({required BuildContext context, required int providerId, required int requestOfferId, required int providerOfferIndex}) async {
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.getUsersChatMessages(providerId: providerId, requestOfferId: requestOfferId);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
serviceProviderOffersList[providerOfferIndex].chatMessages = chatMessages;
Utils.hideLoading(context);
notifyListeners();
@ -269,10 +277,17 @@ class ChatVM extends ChangeNotifier {
}
}
Future<void> getUsersChatMessagesForProvider({required BuildContext context, required int providerId, required int requestOfferId, required int customerRequestIndex}) async {
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.getUsersChatMessages(providerId: providerId, requestOfferId: requestOfferId);
List<ChatMessageModel> chatMessages = await chatRepo.getUsersChatMessages(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId);
context.read<RequestsVM>().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex);
Utils.hideLoading(context);
} catch (e) {

@ -241,7 +241,8 @@ class RequestsVM extends BaseVM {
}
//Request Management
String price = "", description = "";
String price = "",
description = "";
updatePrice(String v) {
price = v;
@ -254,7 +255,9 @@ class RequestsVM extends BaseVM {
Future<VehiclePostingImages> convertFileToRequestPostingImages({required File file}) async {
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
String fileName = file.path
.split('/')
.last;
VehiclePostingImages vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
@ -409,6 +412,7 @@ class RequestsVM extends BaseVM {
required String offerPrice,
required RequestModel requestModel,
required int requestIndex,
required bool isFromChatScreen,
}) async {
if (isSendOfferValidated()) {
final chatVM = context.read<ChatVM>();
@ -421,6 +425,7 @@ class RequestsVM extends BaseVM {
context: context,
);
if (status) {
final senderName = AppState().getUser.data!.userInfo!.firstName;
final senderId = AppState().getUser.data!.userInfo!.userId;
@ -434,15 +439,17 @@ class RequestsVM extends BaseVM {
senderUserID: senderId,
);
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel], context: context);
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestId: requestModel.id,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
requestIndex: requestIndex,
providerIndex: -1,
);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
if (!isFromChatScreen) {
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestId: requestModel.id,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
requestIndex: requestIndex,
providerIndex: -1,
);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}
}
}
}

@ -434,20 +434,19 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
},
),
),
if (adDetailsModel.whatsAppNo != null) ...[
if (adDetailsModel.whatsAppNo != null && adDetailsModel.whatsAppNo!.isNotEmpty) ...[
8.width,
Container(
height: 55,
width: 55,
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
//TODO: It Will be replaced by a WhatsApp Icon
child: const Icon(Icons.message, color: MyColors.black),
height: 55,
width: 55,
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
child: MyAssets.whatsAppIcon.buildSvg()
).onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),
],
if (adDetailsModel.phoneNo != null) ...[
if (adDetailsModel.phoneNo != null && adDetailsModel.phoneNo!.isNotEmpty) ...[
8.width,
Container(
height: 55,
@ -490,7 +489,7 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
//TODO: It Will be replaced by a WhatsApp Icon
child: const Icon(Icons.message, color: MyColors.black),
child: MyAssets.whatsAppIcon.buildSvg()
).onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),

@ -17,14 +17,9 @@ import 'package:provider/provider.dart';
class AppointmentDetailView extends StatelessWidget {
final AppointmentListModel appointmentListModel;
AppointmentDetailView({Key? key, required this.appointmentListModel})
: super(key: key);
const AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key);
Widget getBaseActionButtonWidget(
{required Color color,
required String text,
Color textColor = MyColors.white,
required Function() onPressed}) {
Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) {
return Expanded(
child: ShowFillButton(
maxHeight: 55,
@ -37,26 +32,47 @@ class AppointmentDetailView extends StatelessWidget {
);
}
Widget buildBottomActionButton(
{required AppointmentStatusEnum appointmentStatusEnum,
required BuildContext context}) {
Widget getArrivedBottomActionButton({required BuildContext context, required AppointmentPaymentStatusEnum appointmentPaymentStatusEnum}) {
switch (appointmentPaymentStatusEnum) {
case AppointmentPaymentStatusEnum.notConfirmed:
case AppointmentPaymentStatusEnum.paid:
case AppointmentPaymentStatusEnum.payLater:
case AppointmentPaymentStatusEnum.payPartial:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"),
],
),
);
case AppointmentPaymentStatusEnum.payNow:
return Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Pay Now",
onPressed: () {},
backgroundColor: MyColors.darkPrimaryColor,
txtColor: MyColors.white,
fontSize: 18,
),
);
}
}
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) {
switch (appointmentStatusEnum) {
case AppointmentStatusEnum.booked:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(
color: MyColors.redColor,
onPressed: () => appointmentCancelConfirmationSheet(context),
text: "Cancel"),
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(
context: context,
appointmentId: appointmentListModel.id);
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: "Confirm"),
],
@ -67,36 +83,18 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(
color: MyColors.redColor,
onPressed: () => appointmentCancelConfirmationSheet(context),
text: "Cancel"),
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
],
),
);
case AppointmentStatusEnum.arrived:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(
color: MyColors.grey98Color.withOpacity(0.3),
textColor: MyColors.lightTextColor,
onPressed: () {},
text: "In Progress"),
],
),
);
return getArrivedBottomActionButton(appointmentPaymentStatusEnum: appointmentListModel.appointmentPaymentStatusEnum ?? AppointmentPaymentStatusEnum.notConfirmed, context: context);
case AppointmentStatusEnum.cancelled:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(
color: MyColors.grey98Color.withOpacity(0.3),
textColor: MyColors.lightTextColor,
onPressed: () {},
text: "Cancelled"),
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"),
],
),
);
@ -107,17 +105,12 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(
color: MyColors.redColor,
onPressed: () => appointmentCancelConfirmationSheet(context),
text: "Cancel"),
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(
context: context,
appointmentId: appointmentListModel.id);
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: "Confirm"),
],
@ -132,10 +125,8 @@ class AppointmentDetailView extends StatelessWidget {
final appointmentsVm = context.read<AppointmentsVM>();
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to cancel this appointment?"
.toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle:
"Your appointment will be cancelled and you cannot undo this action.",
title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "Your appointment will be cancelled and you cannot undo this action.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
@ -143,8 +134,7 @@ class AppointmentDetailView extends StatelessWidget {
fontSize: 15,
onPressed: () {
Navigator.pop(context);
appointmentsVm.onCancelAppointmentPressed(
context: context, appointmentListModel: appointmentListModel);
appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
},
),
),
@ -182,8 +172,7 @@ class AppointmentDetailView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
appointmentListModel.providerName!
.toText(fontSize: 16, isBold: true),
appointmentListModel.providerName!.toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -193,23 +182,14 @@ class AppointmentDetailView extends StatelessWidget {
fit: BoxFit.fill,
),
5.width,
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}"
.toText(
fontSize: 12,
isBold: true,
color: MyColors.lightTextColor),
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor),
],
),
13.height,
if (appointmentListModel.appointmentServicesList != null &&
appointmentListModel
.appointmentServicesList!.isNotEmpty) ...[
if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
Column(
children: List.generate(
appointmentListModel.appointmentServicesList!.length,
(index) {
ServiceModel service =
appointmentListModel.appointmentServicesList![index];
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
ServiceModel service = appointmentListModel.appointmentServicesList![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -221,18 +201,14 @@ class AppointmentDetailView extends StatelessWidget {
// fit: BoxFit.fill,
// ),
// 10.width,
"${index + 1}. ${service.providerServiceDescription}"
.toText(fontSize: 14, isBold: true),
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true),
],
),
if (service.serviceItems != null &&
service.serviceItems!.isNotEmpty) ...[
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
Column(
children: List.generate(
service.serviceItems!.length,
(index) =>
"${service.serviceItems![index].name}"
.toText(
(index) => "${service.serviceItems![index].name}".toText(
textAlign: TextAlign.start,
fontSize: 12,
color: MyColors.lightTextColor,
@ -244,22 +220,15 @@ class AppointmentDetailView extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
((service.currentTotalServicePrice).toString())
.toText(fontSize: 25, isBold: true),
((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true),
2.width,
"SAR"
.toText(
color: MyColors.lightTextColor,
fontSize: 16,
isBold: true)
.paddingOnly(bottom: 5),
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
],
).onPress(() => appointmentsVM.priceBreakDownClicked(
context, service)),
).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)),
],
);
}),
@ -271,25 +240,16 @@ class AppointmentDetailView extends StatelessWidget {
CardButtonWithIcon(
title: "Reschedule Appointment",
onCardTapped: () {
context
.read<AppointmentsVM>()
.onRescheduleAppointmentPressed(
context: context,
appointmentListModel: appointmentListModel);
context.read<AppointmentsVM>().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
},
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
),
if (appointmentListModel.appointmentStatusEnum ==
AppointmentStatusEnum.booked) ...[
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
10.width,
CardButtonWithIcon(
title: "Pay for Appointment",
onCardTapped: () {
context
.read<AppointmentsVM>()
.onConfirmAppointmentPressed(
context: context,
appointmentId: appointmentListModel.id);
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
icon: MyAssets.creditCardIcon.buildSvg(),
),
@ -299,10 +259,7 @@ class AppointmentDetailView extends StatelessWidget {
15.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12),
buildBottomActionButton(
appointmentStatusEnum:
appointmentListModel.appointmentStatusEnum!,
context: context),
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
],
),
),

@ -7,6 +7,7 @@ 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/chat_message_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/enums.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
@ -24,6 +25,69 @@ class ChatView extends StatelessWidget {
const ChatView({super.key, required this.chatViewArguments});
Future buildSendOfferBottomSheet(BuildContext context) {
RequestModel requestDetail = chatViewArguments.requestModel!;
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, RequestsVM requestsVM, 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,
TxtField(
value: requestsVM.offerPrice,
errorValue: requestsVM.offerPriceError,
keyboardType: TextInputType.number,
hint: "Enter amount",
onChanged: (v) => requestsVM.updateOfferPrice(v),
),
12.height,
TxtField(
maxLines: 5,
value: requestsVM.offerDescription,
errorValue: requestsVM.offerDescriptionError,
keyboardType: TextInputType.text,
hint: "Description",
onChanged: (v) => requestsVM.updateOfferDescription(v),
),
],
),
25.height,
ShowFillButton(
title: "Submit",
onPressed: () {
requestsVM.onSendOfferPressed(
context: context,
receiverId: requestDetail.customerID,
message: requestsVM.offerDescription,
requestId: requestDetail.id,
offerPrice: requestsVM.offerPrice,
requestModel: requestDetail,
requestIndex: chatViewArguments.requestIndex,
isFromChatScreen: true,
);
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -38,19 +102,34 @@ class ChatView extends StatelessWidget {
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(),
itemCount: chatMessages.length,
separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatMessages[index];
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel);
},
).horPaddingMain(),
),
10.width,
10.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (AppState().currentAppType == AppType.provider) ...[
Expanded(
flex: 1,
child: const Icon(
Icons.local_offer_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(
() async {
buildSendOfferBottomSheet(context);
},
),
),
],
Expanded(
flex: 7,
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: "Type your message here..",
@ -67,6 +146,7 @@ class ChatView extends StatelessWidget {
size: 30,
).onPress(
() async {
log("chatViewArguments.receiverId:${chatViewArguments.receiverId}");
final status = await chatVM.onTextMessageSend(
context: context,
receiverId: chatViewArguments.receiverId,
@ -164,6 +244,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) {
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer:
return Column(
@ -172,75 +253,66 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
chatMessageModel.reqOffer!.price.toString().toText(fontSize: 19, isBold: true),
2.width,
"${chatMessageModel.reqOffer!.price}".toText(fontSize: 19, isBold: true, color: MyColors.white),
5.width,
"SAR".toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
10.height,
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Accept",
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () async {
log("message: ${chatMessageModel.reqOfferID}");
int status = await context.read<ChatVM>().onActionOfferTapped(
context: context,
requestOfferStatusEnum: RequestOfferStatusEnum.accepted,
reqOfferId: chatMessageModel.reqOfferID ?? -1,
);
if (widget.chatMessageModel.isMyMessage == false) ...[
10.height,
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Accept",
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () async {
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(() {});
if (status != -1) {
log("accepted: $status");
if (chatMessageModel.reqOfferID == status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
setState(() {});
}
}
}
},
backgroundColor: MyColors.white,
txtColor: MyColors.greenColor,
),
),
20.width,
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Reject",
borderColor: MyColors.redColor,
isFilled: false,
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(() {});
// }
// }
},
},
backgroundColor: MyColors.white,
txtColor: MyColors.greenColor,
),
),
)
],
),
20.width,
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Reject",
borderColor: MyColors.redColor,
isFilled: false,
backgroundColor: MyColors.white,
txtColor: MyColors.redColor,
fontSize: 9,
onPressed: () async {
buildRejectOfferBottomSheet();
},
),
)
],
),
],
],
);
case RequestOfferStatusEnum.negotiate:
return Column(
children: [
Center(
child: "You asked for the new offer.".toText(
child: "New Offer Required.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
@ -252,7 +324,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return Column(
children: [
Center(
child: "You have accepted the offer.".toText(
child: "Offer has been accepted.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
@ -264,7 +336,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return Column(
children: [
Center(
child: "You have rejected the offer.".toText(
child: "Offer has been rejected.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
@ -276,7 +348,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return Column(
children: [
Center(
child: "You have cancelled the offer.".toText(
child: "Offer has been cancelled.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
@ -291,6 +363,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Widget build(BuildContext context) {
return Directionality(
textDirection: (widget.chatMessageModel.isMyMessage ?? false) ? TextDirection.rtl : TextDirection.ltr,
// textDirection: (widget.chatMessageModel.isMyMessage ?? false) ? TextDirection.rtl : TextDirection.ltr,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -322,10 +395,14 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: (widget.chatMessageModel.chatText ?? "").toText(
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
fontSize: 12,
// isBold: true,
child: Directionality(
textDirection: TextDirection.ltr,
child: (widget.chatMessageModel.chatText ?? "").toText(
color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor,
fontSize: 12,
// isBold: true,
),
),
),
],

@ -1,9 +1,12 @@
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/provider_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/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
@ -88,7 +91,15 @@ class OfferListPage extends StatelessWidget {
final chatVM = context.read<ChatVM>();
await chatVM.getUsersChatMessagesForCustomer(context: context, providerId: offersModel.providerId ?? 0, requestOfferId: 0, providerOfferIndex: index).whenComplete(
await chatVM
.getUsersChatMessagesForCustomer(
context: context,
providerId: offersModel.providerId ?? 0,
requestOfferId: 0,
requestId: offerListPageArguments.requestId ?? 0,
providerOfferIndex: index,
)
.whenComplete(
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true);

@ -34,26 +34,9 @@ class SettingOptionsInviteFriends extends StatelessWidget {
CustomSettingOptionsTile(leadingWidget: const Icon(Icons.person, size: 20), titleText: "Account", onTap: () {}),
],
).toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, margin: const EdgeInsets.fromLTRB(24, 24, 24, 0), borderRadius: 0),
CustomSettingOptionsTile(leadingWidget: const Icon(Icons.translate, size: 20), titleText: "Language", isForLanguage: true, onTap: () {})
.toContainer(width: double.infinity, isShadowEnabled: true, paddingAll: 10, marginAll: 21, borderRadius: 0),
],
),
),
Row(
children: [
Expanded(
child: ShowFillButton(
borderColor: MyColors.redColor,
txtColor: MyColors.redColor,
isFilled: false,
fontSize: 16,
maxHeight: 55,
title: "Log Out",
onPressed: () {},
),
),
],
).paddingAll(21),
],
),
);

@ -33,7 +33,7 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
ClassType type = ClassType.EMAIL;
//TODO: ONLY FOR DEVELOPMENT PURPOSE
String phoneNum = "966504278212", password = "Fa@123";
String phoneNum = "966504278213", password = "Fa@1234";
String email = "";
String countryCode = "";
Country? _country;

@ -93,10 +93,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.17.1"
country_code_picker:
dependency: "direct main"
description:
@ -513,10 +513,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
url: "https://pub.dev"
source: hosted
version: "0.18.1"
version: "0.18.0"
js:
dependency: transitive
description:
@ -601,34 +601,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev"
source: hosted
version: "0.12.16"
version: "0.12.15"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev"
source: hosted
version: "0.5.0"
message_pack_dart:
dependency: transitive
description:
name: message_pack_dart
sha256: "71b9f0ff60e5896e60b337960bb535380d7dba3297b457ac763ccae807385b59"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "0.2.0"
meta:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.9.1"
mime:
dependency: transitive
description:
@ -725,6 +717,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.7"
percent_indicator:
dependency: "direct main"
description:
name: percent_indicator
sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c
url: "https://pub.dev"
source: hosted
version: "4.2.3"
permission_handler:
dependency: "direct main"
description:
@ -789,14 +789,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.6"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
provider:
dependency: "direct main"
description:
@ -877,14 +869,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.1"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
shimmer:
dependency: "direct main"
description:
@ -893,14 +877,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
signalr_netcore:
signalr_core:
dependency: "direct main"
description:
name: signalr_netcore
sha256: "8f84b4b516c03f3a6872f94e9729d1441d5d223a77c81d0a7d7dae5dd0ce1f2f"
name: signalr_core
sha256: dca676372a00c051511591ed0e24521ff7aa4e9320a7fa778a1007f7f522c8c0
url: "https://pub.dev"
source: hosted
version: "1.3.6"
version: "1.1.1"
simple_gesture_detector:
dependency: transitive
description:
@ -926,10 +910,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.9.1"
sqflite:
dependency: transitive
description:
@ -946,38 +930,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.5.0"
sse:
sse_client:
dependency: transitive
description:
name: sse
sha256: "3ff9088cac3f45aa8b91336f1962e3ea6c81baaba0bbba361c05f8aa7fb59442"
name: sse_client
sha256: "71bd826430b41ab20a69d85bf2dfe9f11cfe222938e681ada1aea71fc8adf348"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
sse_channel:
dependency: transitive
description:
name: sse_channel
sha256: ba2b1382b9423c58fa83e1f01a3a40fbaa16a0594aa984870c88bad0b45d4ca4
url: "https://pub.dev"
source: hosted
version: "0.0.3"
version: "0.1.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.11.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
stream_transform:
dependency: transitive
description:
@ -1022,10 +998,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev"
source: hosted
version: "0.6.1"
version: "0.5.1"
tuple:
dependency: transitive
description:
@ -1130,14 +1106,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.3.0"
web_socket_channel:
dependency: transitive
description:
@ -1171,5 +1139,5 @@ packages:
source: hosted
version: "6.3.0"
sdks:
dart: ">=3.2.0-194.0.dev <4.0.0"
dart: ">=3.0.0 <4.0.0"
flutter: ">=3.10.0"

Loading…
Cancel
Save