Merge remote-tracking branch 'origin/mirza_development' into faiz_development

# Conflicts:
#	lib/config/customer_dependencies.dart
#	lib/config/customer_routes.dart
#	lib/main.dart
#	lib/views/dashboard/dashboard_page.dart
aamir_dev
Faiz Hashmi 2 years ago
commit a47cae92f2

@ -1,5 +1,7 @@
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 {
@ -8,5 +10,6 @@ class CustomerDependencies {
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<AppointmentRepo>(() => ScheduleRepoImp());
}
}

@ -7,6 +7,7 @@ import 'package:car_customer_app/views/appointments/review_appointment_view.dart
import 'package:car_customer_app/views/dashboard/dashboard_page.dart';
import 'package:car_customer_app/views/provider/branch_detail_page.dart';
import 'package:car_customer_app/views/provider/provider_profile_page.dart';
import 'package:car_customer_app/views/requests/create_request_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
@ -19,7 +20,9 @@ import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart';
import 'package:mc_common_app/views/payments/payment_methods_view.dart';
import 'package:mc_common_app/views/advertisement/ads_filter_view.dart';
class CustomerAppRoutes {
import '../views/requests/offer_list_page.dart';
class CustomerAppRoutes {
static final Map<String, WidgetBuilder> routes = {
AppRoutes.dashboard: (context) => DashboardPage(),
AppRoutes.bookProviderAppView: (context) => BookProviderAppView(),
@ -37,5 +40,7 @@ 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.createRequestPage: (context) => CreateRequestPage(),
};
}

@ -2,8 +2,11 @@ import 'package:car_customer_app/config/customer_dependencies.dart';
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';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -65,6 +68,8 @@ Future<void> main() async {
ChangeNotifierProvider<PaymentVM>(
create: (_) => PaymentVM(paymentService: injector.get<PaymentService>(), paymentRepo: injector.get<PaymentsRepo>()),
),
scheduleRepo: injector.get<AppointmentRepo>(),
],
child: MyApp(),
).setupLocale(),

@ -0,0 +1,138 @@
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,
};
}

@ -0,0 +1,45 @@
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';
abstract class RequestRepo {
Future<GenericRespModel> createRequest(Map<String, dynamic> map);
Future<List<Request>> getRequests(Map<String, dynamic> postParams);
}
class RequestRepoImp implements RequestRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<GenericRespModel> createRequest(Map<String, dynamic> postParams) async {
GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.createRequest,
postParams,
token: appState.getUser.data!.accessToken,
);
return enumGenericModel;
}
@override
Future<List<Request>> 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(
enumGenericModel.data.length,
(index) => Request.fromJson(
enumGenericModel.data[index],
),
);
return requests;
}
}

@ -0,0 +1,272 @@
import 'dart:io';
import 'package:car_customer_app/repositories/request_repo.dart';
import 'package:mc_common_app/classes/app_state.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/generic_resp_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/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;
final RequestRepo requestRepo;
RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo});
List<FilterListModel> requestsFilterOptions = [];
populateRequestsFilterList() {
requestsFilterOptions.clear();
requestsFilterOptions = [
FilterListModel(title: "Cars", isSelected: true, id: 1),
FilterListModel(title: "Spare Parts", isSelected: false, id: 2),
];
notifyListeners();
}
applyFilterOnRequestsVM({required int index}) {
if (requestsFilterOptions.isEmpty) return;
for (var value in requestsFilterOptions) {
value.isSelected = false;
}
requestsFilterOptions[index].isSelected = true;
notifyListeners();
}
List<File> pickedVehicleImages = [];
String vehicleImageError = "";
void removeImageFromList(String filePath) {
int index = pickedVehicleImages.indexWhere((element) => element.path == filePath);
if (index == -1) {
return;
}
pickedVehicleImages.removeAt(index);
notifyListeners();
}
void pickMultipleImages() async {
List<File> Images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(Images);
if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
notifyListeners();
}
bool isFetchingRequestType = false;
bool isFetchingVehicleType = true;
bool isFetchingVehicleDetail = false;
List<Enums> requestTypes = [];
List<VehicleTypeModel> vehicleTypes = [];
VehicleDetailsModel? vehicleDetails;
List<VehicleBrandsModel> vehicleBrands = [];
List<VehicleModel> vehicleModels = [];
List<VehicleYearModel> vehicleModelYears = [];
List<VehicleCountryModel> vehicleCountries = [];
List<VehicleCityModel> vehicleCities = [];
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();
notifyListeners();
}
SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
Future<void> getVehicleTypes() async {
reset();
isFetchingVehicleType = true;
vehicleTypes = await commonRepo.getVehicleTypes();
isFetchingVehicleType = false;
notifyListeners();
}
reset() {
vehicleTypeId.selectedId = -1;
vehicleBrandId.selectedId = -1;
vehicleModelId.selectedId = -1;
vehicleModelYearId.selectedId = -1;
vehicleCountryId.selectedId = -1;
vehicleCityId.selectedId = -1;
}
void updateSelectionVehicleTypeId(SelectionModel id) async {
vehicleTypeId = id;
getVehicleBrandsByVehicleTypeId();
notifyListeners();
}
Future<void> getVehicleBrandsByVehicleTypeId() async {
// if (vehicleBrandId.selectedId == -1) {
// return;
// }
isFetchingVehicleDetail = true;
notifyListeners();
vehicleDetails = await commonRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId);
if (vehicleDetails != null) {
vehicleBrands = vehicleDetails!.vehicleBrands!;
vehicleModels = vehicleDetails!.vehicleModels!;
vehicleModelYears = vehicleDetails!.vehicleModelYears!;
vehicleCountries = vehicleDetails!.vehicleCountries!;
}
isFetchingVehicleDetail = false;
notifyListeners();
}
SelectionModel vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleBrandId(SelectionModel id) {
vehicleBrandId = id;
vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
notifyListeners();
}
SelectionModel vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleModelId(SelectionModel id) {
vehicleModelId = id;
vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
notifyListeners();
}
SelectionModel vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleModelYearId(SelectionModel id) {
vehicleModelYearId = id;
notifyListeners();
}
bool isShippingDeliveryEnabled = false;
void updateShippingDeliverEnabled(bool v) {
isShippingDeliveryEnabled = v;
notifyListeners();
}
bool isCountryFetching = false;
SelectionModel vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleCountryId(SelectionModel id) async {
vehicleCountryId = id;
isCountryFetching = true;
notifyListeners();
vehicleCities = await commonRepo.getVehicleCities(countryId: vehicleCountryId.selectedId);
isCountryFetching = false;
notifyListeners();
}
SelectionModel vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleCityId(SelectionModel id) {
vehicleCityId = id;
notifyListeners();
}
//Request Management
String price = "", description = "";
updatePrice(String v) {
price = v;
}
updateDescription(String v) {
description = v;
}
Future<GenericRespModel?> createRequest() async {
if (validate()) {
Map<String, dynamic> m = {
"customerID": AppState().getUser.data!.userInfo!.customerId ?? 0,
"requestType": requestTypeId.selectedId,
"vehicleTypeID": vehicleTypeId.selectedId,
"brand": vehicleBrandId.selectedOption,
"model": vehicleModelId.selectedOption,
"year": vehicleModelYearId.selectedOption,
"isNew": true,
"countryID": vehicleCountryId.selectedId,
"cityID": vehicleCityId.selectedId,
"price": price,
"description": description,
"isSpecialServiceNeeded": false,
"requestImages": []
};
GenericRespModel respModel = await requestRepo.createRequest(m);
return respModel;
} else {
return null;
}
}
bool validate() {
bool isValid = true;
if (requestTypeId.selectedId == -1) {
Utils.showToast("Please select valid Request Type");
isValid = false;
} else if (vehicleTypeId.selectedId == -1) {
Utils.showToast("Please select valid Vehicle Type");
isValid = false;
} else if (vehicleBrandId.selectedId == -1) {
Utils.showToast("Please select valid Brand");
isValid = false;
} else if (vehicleModelId.selectedId == -1) {
Utils.showToast("Please select valid Model");
isValid = false;
} else if (vehicleModelYearId.selectedId == -1) {
Utils.showToast("Please select valid Year");
isValid = false;
} else if (vehicleCountryId.selectedId == -1) {
Utils.showToast("Please select valid Country");
isValid = false;
} else if (vehicleCityId.selectedId == -1) {
Utils.showToast("Please select valid City");
isValid = false;
} else if (price.isEmpty) {
Utils.showToast("Please add valid Price");
isValid = false;
} else if (description.isEmpty) {
Utils.showToast("Please add valid Description");
isValid = false;
}
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();
}
}

@ -1,7 +1,9 @@
import 'dart:async';
import 'package:car_customer_app/config/customer_routes.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';
import 'package:car_customer_app/views/dashboard/fragments/ads_fragment.dart';
import 'package:car_customer_app/views/dashboard/fragments/appointments_fragment.dart';
import 'package:car_customer_app/views/dashboard/fragments/home_fragment.dart';
@ -19,6 +21,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'fragments/branches_fragment.dart';
import 'fragments/requests_fragment.dart';
class DashboardPage extends StatefulWidget {
const DashboardPage({Key? key}) : super(key: key);
@ -37,6 +40,8 @@ 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();
});
@ -79,7 +84,7 @@ class _DashboardPageState extends State<DashboardPage> {
const AppointmentsFragment(),
const HomeFragment(),
AdsFragment(),
const SettingsFragment(),
RequestsFragment(),
];
String getPageTitle(int index) {
@ -96,7 +101,7 @@ class _DashboardPageState extends State<DashboardPage> {
return "Ads";
}
if (index == 4) {
return "";
return "My Requests";
}
return "";
}
@ -130,6 +135,19 @@ 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,
);
}
}

@ -0,0 +1,63 @@
import 'package:car_customer_app/view_models/requests_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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,
),
),
)
],
);
}),
);
}
}

@ -42,7 +42,7 @@ class CustomBottomNavbar extends StatelessWidget {
BottomNavigationBarItem(
icon: SvgPicture.asset(MyAssets.settingsIcon).paddingAll(5),
activeIcon: SvgPicture.asset(MyAssets.settingsIcon, color: MyColors.darkIconColor).paddingAll(5),
label: LocaleKeys.settings.tr(),
label: LocaleKeys.requests.tr(),
),
],
currentIndex: dashboardVM.selectedNavbarBarIndex,

@ -0,0 +1,249 @@
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) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Vehicle Detail".toText(fontSize: 18, isBold: true),
8.height,
if (model.isFetchingRequestType) ...[
Center(
child: CircularProgressIndicator(),
),
] else ...[
Builder(builder: (context) {
List<DropValue> requestTypeDrop = [];
for (var element in model.requestTypes) {
requestTypeDrop.add(DropValue(element.enumValue.toInt() ?? 0, element.enumValueStr ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionRequestTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: requestTypeDrop,
dropdownValue: model.requestTypeId.selectedId != -1 ? DropValue(model.requestTypeId.selectedId, model.requestTypeId.selectedOption, "") : null,
hint: "Request Type",
errorValue: model.requestTypeId.errorValue,
);
}),
],
8.height,
if (model.requestTypeId.selectedId != -1)
if (model.isFetchingVehicleType) ...[
Center(
child: CircularProgressIndicator(),
),
] else ...[
Builder(builder: (context) {
List<DropValue> vehicleTypeDrop = [];
for (var element in model.vehicleTypes) {
vehicleTypeDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTypeDrop,
dropdownValue: model.vehicleTypeId.selectedId != -1 ? DropValue(model.vehicleTypeId.selectedId, model.vehicleTypeId.selectedOption, "") : null,
hint: "Vehicle Type",
errorValue: model.vehicleTypeId.errorValue,
);
}),
],
8.height,
if (model.vehicleTypeId.selectedId != -1)
if (model.isFetchingVehicleDetail) ...[
Center(
child: CircularProgressIndicator(),
),
] else ...[
Column(
children: [
Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in model.vehicleBrands) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleBrandsDrop,
dropdownValue: model.vehicleBrandId.selectedId != -1 ? DropValue(model.vehicleBrandId.selectedId, model.vehicleBrandId.selectedOption, "") : null,
hint: "Brand",
errorValue: model.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 ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleModelId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleModelsDrop,
dropdownValue: model.vehicleModelId.selectedId != -1 ? DropValue(model.vehicleModelId.selectedId, model.vehicleModelId.selectedOption, "") : null,
hint: "Model",
errorValue: model.vehicleModelId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleYearModelsDrop = [];
for (var element in model.vehicleModelYears) {
vehicleYearModelsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleYearModelsDrop,
dropdownValue: model.vehicleModelYearId.selectedId != -1 ? DropValue(model.vehicleModelYearId.selectedId, model.vehicleModelYearId.selectedOption, "") : null,
hint: "Year",
errorValue: model.vehicleModelYearId.errorValue,
);
}),
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCountriesDrop = [];
for (var element in model.vehicleCountries) {
vehicleCountriesDrop.add(DropValue(element.id?.toInt() ?? 0, element.countryName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleCountryId(SelectionModel(selectedOption: value.value, selectedId: value.id)),
list: vehicleCountriesDrop,
dropdownValue: model.vehicleCountryId.selectedId != -1 ? DropValue(model.vehicleCountryId.selectedId, model.vehicleCountryId.selectedOption, "") : null,
hint: "Country",
errorValue: model.vehicleCountryId.errorValue,
);
}),
if (model.vehicleCountryId.selectedId != -1) ...[
if (model.isCountryFetching) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [const CircularProgressIndicator().paddingAll(10)],
),
] else ...[
8.height,
Builder(builder: (context) {
List<DropValue> vehicleCitiesDrop = [];
for (var element in model.vehicleCities) {
vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => model.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleCitiesDrop,
dropdownValue: model.vehicleCityId.selectedId != -1 ? DropValue(model.vehicleCityId.selectedId, model.vehicleCityId.selectedOption, "") : null,
hint: "City",
errorValue: model.vehicleCityId.errorValue,
);
}),
],
],
8.height,
TxtField(
hint: "Price",
value: model.price,
onChanged: (e) => model.updatePrice(e),
),
8.height,
TxtField(
hint: "Description",
maxLines: 5,
value: model.description,
onChanged: (e) => model.updateDescription(e),
),
8.height,
DottedRectContainer(
onTap: () => context.read<RequestsVM>().pickMultipleImages(),
text: "Attach Image",
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (model.vehicleImageError != "") ...[
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
model.vehicleImageError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10)
],
if (model.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedImagesContainer(
pickedImages: model.pickedVehicleImages,
onCrossPressedPrimary: model.removeImageFromList,
onAddImagePressed: () {
context.read<RequestsVM>().pickMultipleImages();
},
),
],
16.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: model.isShippingDeliveryEnabled,
onChanged: null,
),
"Shipping/Delivery".toText(color: MyColors.darkPrimaryColor, isBold: true, fontSize: 18)
],
).onPress(() {
model.updateShippingDeliverEnabled(!model.isShippingDeliveryEnabled);
}),
],
),
]
],
).toContainer(isShadowEnabled: true, marginAll: 16, paddingAll: 12),
),
),
ShowFillButton(
title: "Create Request",
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());
}
}
},
)
],
);
}),
);
}
}

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class OfferListPage extends StatelessWidget {
@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),
),
);
}
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,
)
],
),
],
),
Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
).toContainer(
isShadowEnabled: true,
);
}
}

@ -0,0 +1,119 @@
import 'package:car_customer_app/model/request.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/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class RequestItem extends StatelessWidget {
Request request;
RequestItem(this.request);
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestStatusChip(request),
6.height,
"${request.brand} ${request.model}".toText(fontSize: 16, isBold: true),
showItem("Model:", "${request.year}"),
showItem("Customer Name:", "${request.customerName}"),
],
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Center(
child: "${request.offerCount}".toText(
color: Colors.white,
isBold: true,
fontSize: 10,
),
).toContainer(
backgroundColor: MyColors.redColor,
borderRadius: 100,
paddingAll: 1,
width: 20,
height: 20,
),
2.height,
request.cityName.toText(
color: MyColors.lightTextColor,
),
"9 Hours Ago".toText(
color: MyColors.lightTextColor,
)
],
)
],
),
showItem("Description: ", request.description),
showItem("Price Range: ", ""),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
request.price.toString().toText(
fontSize: 20,
color: Colors.black,
isBold: true,
),
2.width,
"SAR"
.toText(
color: MyColors.lightTextColor,
fontSize: 10,
)
.paddingOnly(
bottom: 3,
),
],
),
Icon(
Icons.arrow_forward,
color: MyColors.darkIconColor,
size: 18,
),
],
),
],
)
.toContainer(
isShadowEnabled: true,
)
.onPress(() {
navigateWithName(context, AppRoutes.offersListPage);
});
}
Widget showItem(String title, String value) {
return Row(
children: [
title.toText(
color: MyColors.lightTextColor,
),
2.width,
value.toText(
isBold: true,
),
],
);
}
}

@ -0,0 +1,30 @@
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/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;
RequestStatusChip(this.request);
@override
Widget build(BuildContext context) {
return request.requestStatusName
.toText(
fontSize: 8,
color: Colors.white,
)
.toContainer(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
backgroundColor: request.requestStatus == RequestStatus.pending
? MyColors.adPendingStatusColor
: request.requestStatus == RequestStatus.cancelled
? MyColors.redColor
: MyColors.greenColor,
borderRadius: 100,
);
}
}

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

Loading…
Cancel
Save