Request and Chat WIP

aamir_dev
Faiz Hashmi 2 years ago
parent a47cae92f2
commit 711be7f5da

@ -0,0 +1,195 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
class ChatView extends StatelessWidget {
const ChatView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(title: "Chat"),
body: Column(
children: [
Expanded(
child: ListView.separated(
itemCount: 15,
separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) {
return ChatMessageCustomWidget(
isSent: index.isOdd,
profileUrl: MyAssets.bnCar,
messageText: "Hi, How Are you? I can help you out with the desired request.",
messageTypeEnum: index == 10
? (MessageTypeEnum.newOfferRequired)
: index == 12
? (MessageTypeEnum.offerProvided)
: (MessageTypeEnum.text),
senderName: "Al Abdullah Cars",
);
}).horPaddingMain(),
),
10.width,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 7,
child: TxtField(
// value: adVM.vehicleDemandAmount,
// errorValue: adVM.demandAmountError,
hint: "Type your message here..",
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => null,
),
),
Expanded(
flex: 1,
child: Icon(
Icons.send_rounded,
color: MyColors.darkPrimaryColor,
size: 30,
).onPress(() {}))
],
).toContainer(isShadowEnabled: true),
],
),
// body:
);
}
}
class ChatMessageCustomWidget extends StatelessWidget {
final String profileUrl;
final String senderName;
final String messageText;
final MessageTypeEnum messageTypeEnum;
final bool isSent;
const ChatMessageCustomWidget({
super.key,
required this.profileUrl,
required this.senderName,
required this.messageText,
required this.messageTypeEnum,
required this.isSent,
});
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: isSent ? TextDirection.rtl : TextDirection.ltr,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Image.asset(
profileUrl,
width: 34,
height: 34,
fit: BoxFit.fill,
).toCircle(borderRadius: 100),
),
10.width,
Expanded(
flex: 10,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${isSent ? "You" : senderName}".toText(fontSize: 16, isBold: true),
],
),
5.height,
Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: "${messageText}".toText(
color: isSent ? MyColors.white : MyColors.lightTextColor,
fontSize: 12,
// isBold: true,
),
),
],
),
if (messageTypeEnum == MessageTypeEnum.offerProvided || messageTypeEnum == MessageTypeEnum.newOfferRequired) ...[
5.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"40000".toText(fontSize: 19, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
10.height,
if (messageTypeEnum == MessageTypeEnum.newOfferRequired) ...[
Center(
child: "You asked for the new offer.".toText(
color: MyColors.adPendingStatusColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: MyColors.adPendingStatusColor.withOpacity(0.16)),
] else ...[
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Accept",
fontSize: 9,
borderColor: MyColors.greenColor,
isFilled: false,
onPressed: () {},
backgroundColor: MyColors.white,
txtColor: MyColors.greenColor,
),
),
20.width,
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: "Reject",
borderColor: MyColors.redColor,
isFilled: false,
onPressed: () {},
backgroundColor: MyColors.white,
txtColor: MyColors.redColor,
fontSize: 9,
),
)
],
),
],
],
],
).toContainer(
isShadowEnabled: !isSent,
backgroundColor: isSent ? MyColors.darkIconColor : MyColors.white,
borderRadius: 0,
margin: EdgeInsets.fromLTRB(isSent ? 25 : 0, 0, !isSent ? 25 : 0, 0),
),
],
),
)
],
),
);
}
}
enum MessageTypeEnum { text, picture, offerProvided, recording, video, newOfferRequired }

@ -1,7 +1,6 @@
import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/appointment_repo.dart';
import 'package:car_customer_app/repositories/request_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:mc_common_app/config/dependencies.dart';
class CustomerDependencies {
@ -9,7 +8,6 @@ class CustomerDependencies {
AppDependencies.addDependencies();
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<AppointmentRepo>(() => ScheduleRepoImp());
injector.registerSingleton<RequestRepo>(() => RequestRepoImp());
}
}

@ -1,3 +1,4 @@
import 'package:car_customer_app/chat/chat_view.dart';
import 'package:car_customer_app/views/appointments/appointment_detail_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_schedules_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart';
@ -13,6 +14,7 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/requests/offers_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/advertisement/ads_detail_view.dart';
import 'package:mc_common_app/views/advertisement/create_ad_view.dart';
@ -40,7 +42,8 @@ class CustomerAppRoutes {
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes),
AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel),
AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int),
AppRoutes.offersListPage: (context) => OfferListPage(),
AppRoutes.offersListPage: (context) => OfferListPage(offersList: ModalRoute.of(context)!.settings.arguments as List<OffersModel>),
AppRoutes.createRequestPage: (context) => CreateRequestPage(),
AppRoutes.chatView: (context) => ChatView(),
};
}

@ -3,7 +3,6 @@ import 'package:car_customer_app/config/customer_routes.dart';
import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/appointment_repo.dart';
import 'package:car_customer_app/repositories/request_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:car_customer_app/view_models/requests_view_model.dart';
@ -68,8 +67,13 @@ Future<void> main() async {
ChangeNotifierProvider<PaymentVM>(
create: (_) => PaymentVM(paymentService: injector.get<PaymentService>(), paymentRepo: injector.get<PaymentsRepo>()),
),
scheduleRepo: injector.get<AppointmentRepo>(),
ChangeNotifierProvider<RequestsVM>(
create: (_) => RequestsVM(
requestRepo: injector.get<RequestRepo>(),
commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(),
),
),
],
child: MyApp(),
).setupLocale(),

@ -1,138 +0,0 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class Request {
int requestType;
String requestTypeName;
String requestStatusName;
RequestStatus requestStatus;
String cityName;
String vehicleTypeName;
String countryName;
String customerName;
dynamic serviceProviders;
int offerCount;
int id;
int customerId;
dynamic customer;
String brand;
String model;
int year;
bool isNew;
String description;
List<dynamic> requestImages;
int cityId;
dynamic city;
double price;
int paymentStatus;
int vehicleTypeId;
int countryId;
List<dynamic> requestProviderItem;
bool isActive;
int createdBy;
DateTime createdOn;
dynamic modifiedBy;
dynamic modifiedOn;
Request({
required this.requestType,
required this.requestTypeName,
required this.requestStatusName,
required this.requestStatus,
required this.cityName,
required this.vehicleTypeName,
required this.countryName,
required this.customerName,
required this.serviceProviders,
required this.offerCount,
required this.id,
required this.customerId,
required this.customer,
required this.brand,
required this.model,
required this.year,
required this.isNew,
required this.description,
required this.requestImages,
required this.cityId,
required this.city,
required this.price,
required this.paymentStatus,
required this.vehicleTypeId,
required this.countryId,
required this.requestProviderItem,
required this.isActive,
required this.createdBy,
required this.createdOn,
required this.modifiedBy,
required this.modifiedOn,
});
factory Request.fromJson(Map<String, dynamic> json) => Request(
requestType: json["requestType"],
requestTypeName: json["requestTypeName"],
requestStatusName: json["requestStatusName"],
requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(),
cityName: json["cityName"],
vehicleTypeName: json["vehicleTypeName"],
countryName: json["countryName"],
customerName: json["customerName"],
serviceProviders: json["serviceProviders"],
offerCount: json["offerCount"],
id: json["id"],
customerId: json["customerID"],
customer: json["customer"],
brand: json["brand"],
model: json["model"],
year: json["year"],
isNew: json["isNew"],
description: json["description"],
requestImages: List<dynamic>.from(json["requestImages"].map((x) => x)),
cityId: json["cityID"],
city: json["city"],
price: json["price"],
paymentStatus: json["paymentStatus"],
vehicleTypeId: json["vehicleTypeID"],
countryId: json["countryID"],
requestProviderItem: List<dynamic>.from(json["requestProviderItem"].map((x) => x)),
isActive: json["isActive"],
createdBy: json["createdBy"],
createdOn: DateTime.parse(json["createdOn"]),
modifiedBy: json["modifiedBy"],
modifiedOn: json["modifiedOn"],
);
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,17 @@
import 'package:car_customer_app/model/request.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/models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests/offers_model.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
abstract class RequestRepo {
Future<GenericRespModel> createRequest(Map<String, dynamic> map);
Future<List<Request>> getRequests(Map<String, dynamic> postParams);
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0});
Future<List<RequestModel>> getRequests(Map<String, dynamic> postParams);
}
class RequestRepoImp implements RequestRepo {
@ -27,19 +30,40 @@ class RequestRepoImp implements RequestRepo {
}
@override
Future<List<Request>> getRequests(Map<String, dynamic> postParams) async {
Future<List<RequestModel>> getRequests(Map<String, dynamic> postParams) async {
GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getRequest,
postParams,
token: appState.getUser.data!.accessToken,
);
List<Request> requests = List.generate(
List<RequestModel> requests = List.generate(
enumGenericModel.data.length,
(index) => Request.fromJson(
(index) => RequestModel.fromJson(
enumGenericModel.data[index],
),
);
return requests;
}
@override
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0}) async {
var queryParameters = {
"RequestID": requestId.toString(),
"ServiceProviderID": serviceProviderId.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getRequestOffers,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
List<OffersModel> offersList = List.generate(
genericRespModel.data.length,
(index) => OffersModel.fromJson(
genericRespModel.data[index],
),
);
return offersList;
}
}

@ -9,6 +9,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/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/enums_model.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
@ -218,15 +219,18 @@ class AppointmentsVM extends BaseVM {
serviceAppointmentScheduleList.clear();
}
populateAppointmentsFilterList() {
List<EnumsModel> myAppointmentsEnum = [];
populateAppointmentsFilterList() async {
appointmentsFilterOptions.clear();
appointmentsFilterOptions = [
FilterListModel(title: "All Appointments", isSelected: true, id: -1),
FilterListModel(title: "Booked", isSelected: false, id: 1),
FilterListModel(title: "Confirmed", isSelected: false, id: 2),
FilterListModel(title: "Arrived", isSelected: false, id: 3),
FilterListModel(title: "Cancelled", isSelected: false, id: 4),
];
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.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
notifyListeners();
}
@ -235,9 +239,9 @@ class AppointmentsVM extends BaseVM {
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1 ? 0 : appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true;
appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true;
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1) {
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) {
myFilteredAppointments = myAppointments;
notifyListeners();
return;
@ -247,13 +251,14 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
Future<void> getMyAppointments() async {
isFetchingLists = true;
Future<void> getMyAppointments({bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
myAppointments = await commonRepo.getMyAppointments();
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList();
setState(ViewState.idle);
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
isFetchingLists = false;
notifyListeners();
}
@ -331,12 +336,12 @@ class AppointmentsVM extends BaseVM {
populateBranchesFilterList() {
providersFilterOptions.clear();
providersFilterOptions = [
FilterListModel(title: "All Providers", isSelected: true, id: -1),
FilterListModel(title: "Maintenance", isSelected: false, id: 0),
FilterListModel(title: "Oil Service", isSelected: false, id: 1),
FilterListModel(title: "Accessories", isSelected: false, id: 2),
FilterListModel(title: "Tire Service", isSelected: false, id: 3),
FilterListModel(title: "Dent and Paint", isSelected: false, id: 4),
FilterListModel(title: "All Providers", isSelected: true, id: 0),
FilterListModel(title: "Maintenance", isSelected: false, id: 1),
FilterListModel(title: "Oil Service", isSelected: false, id: 2),
FilterListModel(title: "Accessories", isSelected: false, id: 3),
FilterListModel(title: "Tire Service", isSelected: false, id: 4),
FilterListModel(title: "Dent and Paint", isSelected: false, id: 5),
];
notifyListeners();
}
@ -405,7 +410,6 @@ class AppointmentsVM extends BaseVM {
pickHomeLocationError = "";
if (categoryId != -1) {
isFetchingServices = true;
// notifyListeners();
branchServices = getFilteredBranchServices(categoryId: categoryId);
isFetchingServices = false;
notifyListeners();

@ -1,18 +1,22 @@
import 'dart:convert';
import 'dart:io';
import 'package:car_customer_app/repositories/request_repo.dart';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.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/enums.dart';
import 'package:mc_common_app/models/enums_model.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests/offers_model.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import '../model/request.dart';
class RequestsVM extends BaseVM {
final CommonAppServices commonServices;
final CommonRepo commonRepo;
@ -20,23 +24,49 @@ class RequestsVM extends BaseVM {
RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo});
List<FilterListModel> requestsFilterOptions = [];
List<RequestModel> myRequests = [];
List<RequestModel> myFilteredRequests = [];
List<FilterListModel> requestsTypeFilterOptions = [];
List<EnumsModel> myRequestsTypeEnum = [];
populateRequestsFilterList() async {
requestsTypeFilterOptions.clear();
myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 13 is to get Requests Filter Enums
for (int i = 0; i < myRequestsTypeEnum.length; i++) {
requestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue));
}
notifyListeners();
}
Future<void> getMyRequests({bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
populateRequestsFilterList() {
requestsFilterOptions.clear();
requestsFilterOptions = [
FilterListModel(title: "Cars", isSelected: true, id: 1),
FilterListModel(title: "Spare Parts", isSelected: false, id: 2),
];
myRequests = await requestRepo.getRequests(
{
"customerID": AppState().getUser.data!.userInfo!.customerId,
"pageSize": 100,
"pageIndex": 0,
"requestType": 0,
},
);
applyFilterOnRequestsVM(requestsTypeEnum: RequestsTypeEnum.specialCarRequest);
setState(ViewState.idle);
notifyListeners();
}
applyFilterOnRequestsVM({required int index}) {
if (requestsFilterOptions.isEmpty) return;
for (var value in requestsFilterOptions) {
applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) {
if (requestsTypeFilterOptions.isEmpty) return;
for (var value in requestsTypeFilterOptions) {
value.isSelected = false;
}
requestsFilterOptions[index].isSelected = true;
requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index
myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList();
notifyListeners();
}
@ -62,7 +92,6 @@ class RequestsVM extends BaseVM {
bool isFetchingRequestType = false;
bool isFetchingVehicleType = true;
bool isFetchingVehicleDetail = false;
List<Enums> requestTypes = [];
List<VehicleTypeModel> vehicleTypes = [];
VehicleDetailsModel? vehicleDetails;
List<VehicleBrandsModel> vehicleBrands = [];
@ -73,14 +102,6 @@ class RequestsVM extends BaseVM {
SelectionModel requestTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
getRequestTypes() async {
requestTypeId.selectedId = -1;
isFetchingRequestType = true;
requestTypes = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 16 is to get Request types
isFetchingRequestType = false;
notifyListeners();
}
void updateSelectionRequestTypeId(SelectionModel id) async {
requestTypeId = id;
getVehicleTypes();
@ -90,14 +111,14 @@ class RequestsVM extends BaseVM {
SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
Future<void> getVehicleTypes() async {
reset();
resetRequestCreationForm();
isFetchingVehicleType = true;
vehicleTypes = await commonRepo.getVehicleTypes();
isFetchingVehicleType = false;
notifyListeners();
}
reset() {
resetRequestCreationForm() {
vehicleTypeId.selectedId = -1;
vehicleBrandId.selectedId = -1;
vehicleModelId.selectedId = -1;
@ -191,9 +212,27 @@ class RequestsVM extends BaseVM {
description = v;
}
Future<GenericRespModel?> createRequest() async {
if (validate()) {
Map<String, dynamic> m = {
Future<VehiclePostingImages> convertFileToRequestPostingImages({required File file}) async {
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
VehiclePostingImages vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
imageUrl: file.path,
);
return vehiclePostingImages;
}
Future<void> onCreateRequestTapped(BuildContext context) async {
if (validateCreateRequestForm()) {
Utils.showLoading(context);
List<VehiclePostingImages> vehicleImages = [];
pickedVehicleImages.forEach((element) async {
vehicleImages.add(await convertFileToRequestPostingImages(file: element));
});
Map<String, dynamic> body = {
"customerID": AppState().getUser.data!.userInfo!.customerId ?? 0,
"requestType": requestTypeId.selectedId,
"vehicleTypeID": vehicleTypeId.selectedId,
@ -206,16 +245,26 @@ class RequestsVM extends BaseVM {
"price": price,
"description": description,
"isSpecialServiceNeeded": false,
"requestImages": []
"requestImages": vehicleImages,
};
GenericRespModel respModel = await requestRepo.createRequest(m);
return respModel;
} else {
return null;
try {
GenericRespModel respModel = await requestRepo.createRequest(body);
Utils.hideLoading(context);
if (respModel.messageStatus == 1) {
Utils.showToast("Request Successfully Created");
Navigator.pop(context);
await getMyRequests();
} else {
Utils.showToast(respModel.message.toString());
}
} catch (e, s) {
Utils.hideLoading(context);
print(s);
}
}
}
bool validate() {
bool validateCreateRequestForm() {
bool isValid = true;
if (requestTypeId.selectedId == -1) {
Utils.showToast("Please select valid Request Type");
@ -248,25 +297,16 @@ class RequestsVM extends BaseVM {
return isValid;
}
bool isRequestLoading = true;
List<Request> requests = [];
getRequests() async {
isRequestLoading = true;
notifyListeners();
int selectedRequestType;
// Find the FilterListModel with isSelected equal to true
requests = await requestRepo.getRequests(
{
"customerID": AppState().getUser.data!.userInfo!.customerId,
"pageSize": 100,
"pageIndex": 0,
"requestType": requestsFilterOptions.firstWhere((element) => element.isSelected).id,
},
);
isRequestLoading = false;
notifyListeners();
Future<List<OffersModel>> getOffersByRequest({required int requestId, required BuildContext context}) async {
try {
Utils.showLoading(context);
List<OffersModel> respModel = await requestRepo.getOffersByRequest(requestId: requestId);
Utils.hideLoading(context);
return respModel;
} catch (e) {
Utils.showToast(e.toString());
Utils.hideLoading(context);
return [];
}
}
}

@ -79,6 +79,22 @@ class AppointmentDetailView extends StatelessWidget {
);
case AppointmentStatusEnum.allAppointments:
return SizedBox();
case AppointmentStatusEnum.rescheduled:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
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);
},
text: "Confirm"),
],
),
);
}
}

@ -40,7 +40,6 @@ class _DashboardPageState extends State<DashboardPage> {
scheduleMicrotask(() {
context.read<AppointmentsVM>().populateAppointmentsFilterList();
context.read<AppointmentsVM>().populateBranchesFilterList();
context.read<AppointmentsVM>().populateProvidersFilterList();
context.read<RequestsVM>().populateRequestsFilterList();
context.read<AdVM>().populateAdsFilterList();
_onRefresh();
@ -50,6 +49,7 @@ class _DashboardPageState extends State<DashboardPage> {
Future<void> _onRefresh() async {
AdVM adVM = Provider.of<AdVM>(context, listen: false);
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
RequestsVM requestsVM = Provider.of<RequestsVM>(context, listen: false);
if (appointmentsVM.myAppointments.isEmpty) {
await appointmentsVM.getMyAppointments();
}
@ -62,6 +62,9 @@ class _DashboardPageState extends State<DashboardPage> {
if (adVM.exploreAds.isEmpty) {
await adVM.getExploreAds();
}
if (requestsVM.myRequests.isEmpty) {
await requestsVM.getMyRequests();
}
if (adVM.vehicleTypes.isEmpty) {
await adVM.getVehicleTypes();
@ -135,19 +138,6 @@ class _DashboardPageState extends State<DashboardPage> {
drawer: CustomDrawer(dashboardVM: context.watch<DashboardVM>()),
bottomNavigationBar: CustomBottomNavbar(),
body: fragments[context.watch<DashboardVM>().selectedNavbarBarIndex],
floatingActionButton: context.watch<DashboardVM>().selectedNavbarBarIndex == 4
? FloatingActionButton(
onPressed: () {
if (context.read<DashboardVM>().selectedNavbarBarIndex == 4) {
navigateWithName(context, AppRoutes.createRequestPage);
}
},
child: Icon(
Icons.add,
color: Colors.white,
),
)
: null,
);
}
}

@ -5,7 +5,6 @@ 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/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/widgets_models.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';

@ -8,6 +8,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_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/widgets/common_widgets/categories_list.dart';
import 'package:provider/provider.dart';
@ -27,38 +28,46 @@ class AppointmentsFragment extends StatelessWidget {
children: [
16.height,
FiltersList(
filterList: appointmentsVM.appointmentsFilterOptions,
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()),
),
filterList: appointmentsVM.appointmentsFilterOptions,
onFilterTapped: (index, selectedFilterId) {
appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum());
}),
16.height,
Expanded(
child: appointmentsVM.myFilteredAppointments.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"No Appointments to show.".toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.myFilteredAppointments.length,
itemBuilder: (BuildContext context, int index) {
return BuildAppointmentContainerForCustomer(
onTapped: () {
AppointmentListModel appointmentModel = appointmentsVM.myFilteredAppointments[index];
appointmentModel.appointmentServicesList!.forEach((service) {
double totalServicePrice = 0.0;
service.serviceItems!.forEach((item) {
totalServicePrice = totalServicePrice + (double.parse("${item.price ?? 0.0}"));
});
service.currentTotalServicePrice = totalServicePrice;
});
navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel);
},
appointmentListModel: appointmentsVM.myFilteredAppointments[index],
);
},
),
child: RefreshIndicator(
onRefresh: () async {
appointmentsVM.getMyAppointments(isNeedToRebuild: true);
},
child: appointmentsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: appointmentsVM.myFilteredAppointments.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"No Appointments to show.".toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.myFilteredAppointments.length,
itemBuilder: (BuildContext context, int index) {
return BuildAppointmentContainerForCustomer(
onTapped: () {
AppointmentListModel appointmentModel = appointmentsVM.myFilteredAppointments[index];
appointmentModel.appointmentServicesList!.forEach((service) {
double totalServicePrice = 0.0;
service.serviceItems!.forEach((item) {
totalServicePrice = totalServicePrice + (double.parse("${item.price ?? 0.0}"));
});
service.currentTotalServicePrice = totalServicePrice;
});
navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel);
},
appointmentListModel: appointmentsVM.myFilteredAppointments[index],
);
},
),
),
),
],
);

@ -38,44 +38,35 @@ class BranchesFragment extends StatelessWidget {
onRefresh: () async {
context.read<AppointmentsVM>().getAllNearBranches(isNeedToRebuild: true);
},
child: SingleChildScrollView(
child: Container(
child: Container(
width: double.infinity,
height: MediaQuery.of(context).size.height / 1.37,
child: Consumer<AppointmentsVM>(
builder: (context, model, _) {
if (model.state == ViewState.busy) {
return const Center(child: CircularProgressIndicator());
} else {
return model.nearbyBranches.isEmpty
? Center(child: LocaleKeys.no_branch.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: model.nearbyBranches.length,
itemBuilder: (context, index) {
BranchDetailModel branchDetailModel = model.nearbyBranches[index];
child: appointmentsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: appointmentsVM.nearbyBranches.isEmpty
? Center(child: LocaleKeys.no_branch.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: appointmentsVM.nearbyBranches.length,
itemBuilder: (context, index) {
BranchDetailModel branchDetailModel = appointmentsVM.nearbyBranches[index];
return ProviderDetailsCard(
onCardTapped: () {
navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel);
},
providerImageUrl: MyAssets.bnCar,
title: branchDetailModel.branchName ?? "",
providerLocation: branchDetailModel.distanceKm.toString() + " KM",
providerName: branchDetailModel.serviceProviderName ?? "",
providerRatings: "4.9",
services: branchDetailModel.branchServices,
);
},
separatorBuilder: (context, index) {
return 12.height;
},
padding: const EdgeInsets.all(12),
);
}
},
),
),
),
return ProviderDetailsCard(
onCardTapped: () {
navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel);
},
providerImageUrl: MyAssets.bnCar,
title: branchDetailModel.branchName ?? "",
providerLocation: branchDetailModel.distanceKm.toString() + " KM",
providerName: branchDetailModel.serviceProviderName ?? "",
providerRatings: "4.9",
services: branchDetailModel.branchServices,
);
},
separatorBuilder: (context, index) {
return 12.height;
},
padding: const EdgeInsets.all(12),
)),
),
),
],

@ -1,63 +1,69 @@
import 'package:car_customer_app/view_models/requests_view_model.dart';
import 'package:car_customer_app/views/requests/widget/request_item.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/theme/colors.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:provider/provider.dart';
import '../../requests/widget/request_item.dart';
class RequestsFragment extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Column(
children: [
ShowFillButton(
title: "title",
onPressed: () {
context.read<RequestsVM>().getRequests();
}),
16.height,
FiltersList(
filterList: requestsVM.requestsFilterOptions,
onFilterTapped: (index, selectedFilterId) => requestsVM.applyFilterOnRequestsVM(index: index),
),
8.height,
Expanded(
child: requestsVM.isRequestLoading
? Center(child: CircularProgressIndicator())
: requestsVM.requests.length == 0
? Center(
child: "No Request Available".toText(
isBold: true,
),
)
: ListView.separated(
itemBuilder: (context, index) {
return RequestItem(requestsVM.requests[index]);
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: requestsVM.requests.length,
padding: EdgeInsets.only(
left: 16,
right: 16,
bottom: 16,
top: 8,
return Scaffold(
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Column(
children: [
16.height,
FiltersList(
filterList: requestsVM.requestsTypeFilterOptions,
onFilterTapped: (index, selectedFilterId) {
requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: selectedFilterId.toRequestTypeStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await requestsVM.getMyRequests(isNeedToRebuild: true),
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.separated(
itemBuilder: (context, index) {
return RequestItem(request: requestsVM.myRequests[index]);
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: requestsVM.myRequests.length,
padding: EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
),
),
)
],
);
}),
))
],
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () => navigateWithName(context, AppRoutes.createRequestPage),
backgroundColor: MyColors.darkPrimaryColor,
child: Icon(
Icons.add,
color: MyColors.white,
),
),
);
}
}

@ -1,34 +1,27 @@
import 'package:car_customer_app/view_models/requests_view_model.dart';
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/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/picked_images_container.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/dotted_rect.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
class CreateRequestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// context.read<RequestsVM>().getVehicleTypes();
context.read<RequestsVM>().getRequestTypes();
return Scaffold(
appBar: CustomAppBar(
title: "Create Request",
),
body: Consumer<RequestsVM>(builder: (context, model, widget) {
body: Consumer<RequestsVM>(builder: (context, requestsVM, widget) {
return Column(
children: [
Expanded(
@ -38,49 +31,49 @@ class CreateRequestPage extends StatelessWidget {
children: [
"Vehicle Detail".toText(fontSize: 18, isBold: true),
8.height,
if (model.isFetchingRequestType) ...[
if (requestsVM.isFetchingRequestType) ...[
Center(
child: CircularProgressIndicator(),
),
] else ...[
Builder(builder: (context) {
List<DropValue> requestTypeDrop = [];
for (var element in model.requestTypes) {
for (var element in requestsVM.myRequestsTypeEnum) {
requestTypeDrop.add(DropValue(element.enumValue.toInt() ?? 0, element.enumValueStr ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionRequestTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionRequestTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: requestTypeDrop,
dropdownValue: model.requestTypeId.selectedId != -1 ? DropValue(model.requestTypeId.selectedId, model.requestTypeId.selectedOption, "") : null,
dropdownValue: requestsVM.requestTypeId.selectedId != -1 ? DropValue(requestsVM.requestTypeId.selectedId, requestsVM.requestTypeId.selectedOption, "") : null,
hint: "Request Type",
errorValue: model.requestTypeId.errorValue,
errorValue: requestsVM.requestTypeId.errorValue,
);
}),
],
8.height,
if (model.requestTypeId.selectedId != -1)
if (model.isFetchingVehicleType) ...[
if (requestsVM.requestTypeId.selectedId != -1)
if (requestsVM.isFetchingVehicleType) ...[
Center(
child: CircularProgressIndicator(),
),
] else ...[
Builder(builder: (context) {
List<DropValue> vehicleTypeDrop = [];
for (var element in model.vehicleTypes) {
for (var element in requestsVM.vehicleTypes) {
vehicleTypeDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTypeDrop,
dropdownValue: model.vehicleTypeId.selectedId != -1 ? DropValue(model.vehicleTypeId.selectedId, model.vehicleTypeId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleTypeId.selectedId != -1 ? DropValue(requestsVM.vehicleTypeId.selectedId, requestsVM.vehicleTypeId.selectedOption, "") : null,
hint: "Vehicle Type",
errorValue: model.vehicleTypeId.errorValue,
errorValue: requestsVM.vehicleTypeId.errorValue,
);
}),
],
8.height,
if (model.vehicleTypeId.selectedId != -1)
if (model.isFetchingVehicleDetail) ...[
if (requestsVM.vehicleTypeId.selectedId != -1)
if (requestsVM.isFetchingVehicleDetail) ...[
Center(
child: CircularProgressIndicator(),
),
@ -89,62 +82,62 @@ class CreateRequestPage extends StatelessWidget {
children: [
Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in model.vehicleBrands) {
for (var element in requestsVM.vehicleBrands) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleBrandsDrop,
dropdownValue: model.vehicleBrandId.selectedId != -1 ? DropValue(model.vehicleBrandId.selectedId, model.vehicleBrandId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleBrandId.selectedId != -1 ? DropValue(requestsVM.vehicleBrandId.selectedId, requestsVM.vehicleBrandId.selectedOption, "") : null,
hint: "Brand",
errorValue: model.vehicleBrandId.errorValue,
errorValue: requestsVM.vehicleBrandId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in model.vehicleModels) {
if (model.vehicleBrandId.selectedId == element.vehicleBrandID) vehicleModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.model ?? "", ""));
for (var element in requestsVM.vehicleModels) {
if (requestsVM.vehicleBrandId.selectedId == element.vehicleBrandID) vehicleModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.model ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue: model.vehicleModelId.selectedId != -1 ? DropValue(model.vehicleModelId.selectedId, model.vehicleModelId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleModelId.selectedId != -1 ? DropValue(requestsVM.vehicleModelId.selectedId, requestsVM.vehicleModelId.selectedOption, "") : null,
hint: "Model",
errorValue: model.vehicleModelId.errorValue,
errorValue: requestsVM.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element in model.vehicleModelYears) {
for (var element in requestsVM.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue: model.vehicleModelYearId.selectedId != -1 ? DropValue(model.vehicleModelYearId.selectedId, model.vehicleModelYearId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleModelYearId.selectedId != -1 ? DropValue(requestsVM.vehicleModelYearId.selectedId, requestsVM.vehicleModelYearId.selectedOption, "") : null,
hint: "Year",
errorValue: model.vehicleModelYearId.errorValue,
errorValue: requestsVM.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in model.vehicleCountries) {
for (var element in requestsVM.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.countryName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
(DropValue value) => requestsVM.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue: model.vehicleCountryId.selectedId != -1 ? DropValue(model.vehicleCountryId.selectedId, model.vehicleCountryId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleCountryId.selectedId != -1 ? DropValue(requestsVM.vehicleCountryId.selectedId, requestsVM.vehicleCountryId.selectedOption, "") : null,
hint: "Country",
errorValue: model.vehicleCountryId.errorValue,
errorValue: requestsVM.vehicleCountryId.errorValue,
);
}),
if (model.vehicleCountryId.selectedId != -1) ...[
if (model.isCountryFetching) ...[
if (requestsVM.vehicleCountryId.selectedId != -1) ...[
if (requestsVM.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
@ -153,15 +146,15 @@ class CreateRequestPage extends StatelessWidget {
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element in model.vehicleCities) {
for (var element in requestsVM.vehicleCities) {
vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
(DropValue value) => requestsVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: model.vehicleCityId.selectedId != -1 ? DropValue(model.vehicleCityId.selectedId, model.vehicleCityId.selectedOption, "") : null,
dropdownValue: requestsVM.vehicleCityId.selectedId != -1 ? DropValue(requestsVM.vehicleCityId.selectedId, requestsVM.vehicleCityId.selectedOption, "") : null,
hint: "City",
errorValue: model.vehicleCityId.errorValue,
errorValue: requestsVM.vehicleCityId.errorValue,
);
}),
],
@ -169,15 +162,15 @@ class CreateRequestPage extends StatelessWidget {
8.height,
TxtField(
hint: "Price",
value: model.price,
onChanged: (e) => model.updatePrice(e),
value: requestsVM.price,
onChanged: (e) => requestsVM.updatePrice(e),
),
8.height,
TxtField(
hint: "Description",
maxLines: 5,
value: model.description,
onChanged: (e) => model.updateDescription(e),
value: requestsVM.description,
onChanged: (e) => requestsVM.updateDescription(e),
),
8.height,
DottedRectContainer(
@ -185,20 +178,20 @@ class CreateRequestPage extends StatelessWidget {
text: "Attach Image",
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (model.vehicleImageError != "") ...[
if (requestsVM.vehicleImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
model.vehicleImageError.toText(fontSize: 14, color: Colors.red),
requestsVM.vehicleImageError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
if (model.pickedVehicleImages.isNotEmpty) ...[
if (requestsVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedImagesContainer(
pickedImages: model.pickedVehicleImages,
onCrossPressedPrimary: model.removeImageFromList,
pickedImages: requestsVM.pickedVehicleImages,
onCrossPressedPrimary: requestsVM.removeImageFromList,
onAddImagePressed: () {
context.read<RequestsVM>().pickMultipleImages();
},
@ -209,13 +202,14 @@ class CreateRequestPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: model.isShippingDeliveryEnabled,
value: requestsVM.isShippingDeliveryEnabled,
onChanged: null,
),
"Shipping/Delivery".toText(color: MyColors.darkPrimaryColor, isBold: true, fontSize: 18)
],
).onPress(() {
model.updateShippingDeliverEnabled(!model.isShippingDeliveryEnabled);
requestsVM.updateShippingDeliverEnabled(!requestsVM.isShippingDeliveryEnabled);
}),
],
),
@ -229,16 +223,7 @@ class CreateRequestPage extends StatelessWidget {
maxWidth: double.infinity,
margin: EdgeInsets.all(16),
onPressed: () async {
Utils.showLoading(context);
GenericRespModel? response = await model.createRequest();
Utils.hideLoading(context);
if (response != null) {
if (response.messageStatus == 1) {
Utils.showToast("Request Successfully Created");
} else {
Utils.showToast(response.message.toString());
}
}
await context.read<RequestsVM>().onCreateRequestTapped(context);
},
)
],

@ -1,84 +1,87 @@
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/offers_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class OfferListPage extends StatelessWidget {
final List<OffersModel> offersList;
OfferListPage({required this.offersList});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Offers",
),
body: ListView.separated(
itemBuilder: (context, index) {
return showOfferItem();
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: 2,
padding: EdgeInsets.all(16),
),
);
}
appBar: CustomAppBar(title: "Offers"),
body: offersList.isEmpty
? Center(child: "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: offersList.length,
padding: EdgeInsets.all(16),
itemBuilder: (context, index) {
OffersModel offersModel = offersList[index];
return Stack(
alignment: Alignment.bottomRight,
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${offersModel.serviceProvider!.companyName ?? ""}".toText(fontSize: 16, isBold: true),
Widget showOfferItem() {
return Stack(
alignment: Alignment.bottomRight,
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Toyota Corolla".toText(fontSize: 16, isBold: true),
Center(
child: "2".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 20,
height: 20,
),
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child:
"Dear, how you doing. I have great offer for You for this car. Dear, how you doing. I have great offer for You for this car. Dear, how you doing. I have great offer for You for this car. Dear, how you doing. I have great offer for You for this car. Dear, how you doing. I have great offer for You for this car."
.toText(
color: MyColors.lightTextColor,
fontSize: 12,
),
),
12.width,
"9 Hours Ago".toText(
color: MyColors.lightTextColor,
)
],
//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,
// ),
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: "${offersModel.comment} and This is dummy text edition.".toText(
color: MyColors.lightTextColor,
fontSize: 12,
),
),
12.width,
"9 Hours Ago".toText(
color: MyColors.lightTextColor,
)
],
),
],
),
Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
).onPress(() {
navigateWithName(context, AppRoutes.chatView);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
],
),
Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
).toContainer(
isShadowEnabled: true,
);
}
}

@ -1,17 +1,21 @@
import 'package:car_customer_app/model/request.dart';
import 'package:car_customer_app/view_models/requests_view_model.dart';
import 'package:car_customer_app/views/requests/widget/request_status_chip.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/offers_model.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class RequestItem extends StatelessWidget {
Request request;
final RequestModel request;
RequestItem(this.request);
RequestItem({required this.request});
@override
Widget build(BuildContext context) {
@ -25,7 +29,7 @@ class RequestItem extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestStatusChip(request),
Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)),
6.height,
"${request.brand} ${request.model}".toText(fontSize: 16, isBold: true),
showItem("Model:", "${request.year}"),
@ -37,19 +41,21 @@ class RequestItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Center(
child: "${request.offerCount}".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
if (request.offerCount > 0) ...[
Center(
child: "${request.offerCount}".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 20,
height: 20,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 20,
height: 20,
),
],
2.height,
request.cityName.toText(
color: MyColors.lightTextColor,
@ -94,12 +100,9 @@ class RequestItem extends StatelessWidget {
],
),
],
)
.toContainer(
isShadowEnabled: true,
)
.onPress(() {
navigateWithName(context, AppRoutes.offersListPage);
).toContainer(isShadowEnabled: true).onPress(() async {
List<OffersModel> offers = await context.read<RequestsVM>().getOffersByRequest(requestId: request.id, context: context);
navigateWithName(context, AppRoutes.offersListPage, arguments: offers);
});
}

@ -1,12 +1,12 @@
import 'package:car_customer_app/model/request.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class RequestStatusChip extends StatelessWidget {
Request request;
RequestModel request;
RequestStatusChip(this.request);

@ -37,7 +37,7 @@ dependencies:
table_calendar: ^3.0.9
mc_common_app:
path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app
path: /Volumes/Data/Projects/Flutter/car_common_app
dev_dependencies:
flutter_test:

Loading…
Cancel
Save