From 50baaacb74dbf1edac06b5ae3603b2e110737c8b Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Wed, 14 Jun 2023 14:40:50 +0300 Subject: [PATCH 1/4] Design in Progress For Appointment Module. --- lib/config/customer_dependencies.dart | 1 - lib/config/customer_routes.dart | 6 +- lib/view_models/appointments_view_model.dart | 23 ++ .../appointment_services_list_view.dart | 155 +++++++++ .../book_appointment_services_view.dart | 325 ------------------ .../book_appointments_item_view.dart | 113 ++++++ ...appointment_service_pick_bottom_sheet.dart | 194 +++++++++++ .../service_item_with_price_checkbox.dart | 51 +++ 8 files changed, 540 insertions(+), 328 deletions(-) create mode 100644 lib/views/appointments/appointment_services_list_view.dart delete mode 100644 lib/views/appointments/book_appointment_services_view.dart create mode 100644 lib/views/appointments/book_appointments_item_view.dart create mode 100644 lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart create mode 100644 lib/views/appointments/widgets/service_item_with_price_checkbox.dart diff --git a/lib/config/customer_dependencies.dart b/lib/config/customer_dependencies.dart index 53792ef..5d7ec56 100644 --- a/lib/config/customer_dependencies.dart +++ b/lib/config/customer_dependencies.dart @@ -3,6 +3,5 @@ import 'package:mc_common_app/config/dependencies.dart'; class CustomerDependencies { static void addDependencies() { AppDependencies.addDependencies(); - } } diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index 3345264..bcf7484 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -1,5 +1,6 @@ import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; -import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; +import 'package:car_customer_app/views/appointments/appointment_services_list_view.dart'; +import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:flutter/cupertino.dart'; @@ -17,7 +18,8 @@ class CustomerAppRoutes { AppRoutes.appointmentDetailView: (context) => AppointmentDetailView(appointmentListModel: ModalRoute.of(context)!.settings.arguments as AppointmentListModel), AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel), AppRoutes.createAdView: (context) => CreateAdView(), - AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), + AppRoutes.bookAppointmenServicesView: (context) => AppointmentServicesListView(), + AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), }; } diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index 2fb9aa2..94d836c 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,4 +1,5 @@ import 'package:flutter/cupertino.dart'; +import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/provider_category_model.dart'; import 'package:mc_common_app/models/provider_service_model.dart'; @@ -29,9 +30,16 @@ class AppointmentsVM extends ChangeNotifier { } String pickedHomeLocation = ""; + String pickHomeLocationError = ""; void updatePickedHomeLocation(String value) { pickedHomeLocation = value; + pickHomeLocationError = ""; + notifyListeners(); + } + + void updatePickHomeLocationError(String value) { + pickHomeLocationError = value; notifyListeners(); } @@ -58,10 +66,25 @@ class AppointmentsVM extends ChangeNotifier { notifyListeners(); } + bool isServiceSelectionValidated() { + if (providerServiceId.selectedId == -1) { + return false; + } + + if (isHomeTapped) { + if (pickedHomeLocation == "") { + updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError); + return false; + } + } + return true; + } + getProviderServices(int categoryId) async { providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); isHomeTapped = false; pickedHomeLocation = ""; + pickHomeLocationError = ""; if (categoryId != -1) { isFetchingServices = true; notifyListeners(); diff --git a/lib/views/appointments/appointment_services_list_view.dart b/lib/views/appointments/appointment_services_list_view.dart new file mode 100644 index 0000000..c2aae69 --- /dev/null +++ b/lib/views/appointments/appointment_services_list_view.dart @@ -0,0 +1,155 @@ +import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart'; +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/models/widgets_models.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class AppointmentServicesListView extends StatelessWidget { + AppointmentServicesListView({Key? key}) : super(key: key); + + void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return AppointmentServicePickBottomSheet(); + }, + ); + } + + final _dummySlots = [ + TimeSlotModel(isSelected: false, slotId: 1, slot: "11:00"), + TimeSlotModel(isSelected: false, slotId: 2, slot: "12:00"), + TimeSlotModel(isSelected: true, slotId: 3, slot: "13:00"), + TimeSlotModel(isSelected: false, slotId: 4, slot: "14:00"), + TimeSlotModel(isSelected: false, slotId: 5, slot: "15:00"), + TimeSlotModel(isSelected: false, slotId: 6, slot: "16:00"), + TimeSlotModel(isSelected: false, slotId: 7, slot: "17:00"), + TimeSlotModel(isSelected: false, slotId: 8, slot: "18:00"), + TimeSlotModel(isSelected: false, slotId: 9, slot: "19:00"), + TimeSlotModel(isSelected: false, slotId: 10, slot: "20:00"), + TimeSlotModel(isSelected: false, slotId: 11, slot: "21:00"), + TimeSlotModel(isSelected: false, slotId: 12, slot: "22:00"), + TimeSlotModel(isSelected: false, slotId: 13, slot: "23:00"), + TimeSlotModel(isSelected: false, slotId: 14, slot: "24:00"), + TimeSlotModel(isSelected: false, slotId: 15, slot: "25:00"), + TimeSlotModel(isSelected: false, slotId: 16, slot: "26:00"), + TimeSlotModel(isSelected: false, slotId: 17, slot: "27:00"), + TimeSlotModel(isSelected: false, slotId: 18, slot: "28:00"), + TimeSlotModel(isSelected: false, slotId: 19, slot: "29:00"), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Book Appointment", + isRemoveBackButton: false, + isDrawerEnabled: false, + actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], + onBackButtonTapped: () => Navigator.pop(context), + ), + body: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 21.height, + CustomAddButton( + onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM), + text: "Add Services", + icon: Container( + height: 24, + width: 24, + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), + child: const Icon(Icons.add, color: MyColors.white), + ), + ).horPaddingMain(), + 10.height, + ListView.builder( + shrinkWrap: true, + itemCount: 20, + itemBuilder: (BuildContext context, int index) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: "Mechanic".toText(fontSize: 16, isBold: true), + ), + Align( + alignment: Alignment.topRight, + child: MyAssets.icEdit.buildSvg(fit: BoxFit.fill, height: 19, width: 19), + ).onPress(() {}), + ], + ), + Builder(builder: (context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (true) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + ("Home").toText(fontSize: 12, isBold: true).expand(), + ], + ), + 8.height, + Column( + children: List.generate( + 5, + (index) => Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Gear Kit: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + ("200 SAR").toText(fontSize: 12, isBold: true).expand(), + ], + ), + ), + ), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "120".toText(fontSize: 29, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + ], + ), + ], + if (true) ...[ + 8.height, + ("Available Slots").toText(fontSize: 14, isBold: true), + 5.height, + SizedBox( + width: double.infinity, + child: BuildTimeSlots( + timeSlots: _dummySlots, + onPressed: (index) => null, + ), + ), + ], + ], + ); + }), + ], + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); + }, + ).expand() + ], + ); + }, + )); + } +} diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart deleted file mode 100644 index 71f4bb3..0000000 --- a/lib/views/appointments/book_appointment_services_view.dart +++ /dev/null @@ -1,325 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -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/models/widgets_models.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/views/advertisement/custom_add_button.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/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:provider/provider.dart'; - -class BookAppointmentServicesView extends StatelessWidget { - const BookAppointmentServicesView({Key? key}) : super(key: key); - - void openTheAddServiceBottomSheet(BuildContext context) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (BuildContext context) { - AppointmentsVM appointmentsVM = context.watch(); - return SizedBox( - height: MediaQuery.of(context).size.height * 0.85, - child: Column( - children: [ - Container( - margin: const EdgeInsets.all(8), - height: 8, - width: 60, - decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))), - ), - 12.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "Select Category".toText(fontSize: 24, isBold: true), - ], - ), - 30.height, - Expanded( - child: ListView( - children: [ - Builder( - builder: (context) { - List serviceCategories = []; - for (var element in appointmentsVM.providerCategories) { - if (!element.isSelected!) { - serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.categoryName ?? "", "")); - } - } - return DropdownField( - (DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), - list: serviceCategories, - hint: "Select Category", - dropdownValue: appointmentsVM.providerCategoryId.selectedId != -1 - ? DropValue(appointmentsVM.providerCategoryId.selectedId, appointmentsVM.providerCategoryId.selectedOption, "") - : null, - ); - }, - ), - if (appointmentsVM.isFetchingServices) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [const CircularProgressIndicator().paddingAll(10)], - ), - ] else if (appointmentsVM.providerServices.isNotEmpty) ...[ - 8.height, - Builder( - builder: (context) { - List serviceCategories = []; - for (var element in appointmentsVM.providerServices) { - if (!element.isSelected!) { - serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.id.toString(), "")); - } - } - return DropdownField( - (DropValue value) => appointmentsVM.updateProviderServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), - list: serviceCategories, - hint: "Select Services", - dropdownValue: appointmentsVM.providerServiceId.selectedId != -1 - ? DropValue(appointmentsVM.providerServiceId.selectedId, appointmentsVM.providerServiceId.selectedOption, "") - : null, - ); - }, - ), - ], - if (appointmentsVM.providerServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ - 16.height, - Row( - children: [ - "Select Service Location".toText( - fontSize: 16, - isBold: true, - color: MyColors.black, - ), - ], - ), - 8.height, - Row( - children: [ - Expanded( - child: ShowFillButton( - isFilled: appointmentsVM.isHomeTapped, - maxHeight: 48, - title: "Home", - txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, - onPressed: () => appointmentsVM.updateIsHomeTapped(true), - ), - ), - 12.width, - Expanded( - child: ShowFillButton( - isFilled: !appointmentsVM.isHomeTapped, - txtColor: !appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, - maxHeight: 48, - title: "Workshop", - onPressed: () => appointmentsVM.updateIsHomeTapped(false), - ), - ), - ], - ), - if (appointmentsVM.isHomeTapped) ...[ - 8.height, - TxtField( - hint: 'Pick Home Location', - value: appointmentsVM.pickedHomeLocation, - isNeedClickAll: true, - postfixData: Icons.location_on, - postFixDataColor: MyColors.darkTextColor, - onTap: () { - //TODO: open the place picked to pick the location and save it in provider. - appointmentsVM.updatePickedHomeLocation("PM58+F97, Al Olaya, Riyadh 12333"); - }, - ), - 14.height, - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Icon( - Icons.warning, - color: MyColors.adPendingStatusColor, - size: 19, - ).paddingOnly(bottom: 2), - 3.width, - "Some services are not available on home location.".toText( - color: MyColors.adPendingStatusColor, - fontSize: 12, - isItalic: true, - ), - ], - ), - ] - ], - ], - ), - ), - SizedBox( - width: double.infinity, - child: Column( - children: [ - if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[ - const Divider(thickness: 1, height: 1), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - // TODO: This Price will be decided according to the service selected - 150.toString().toText(fontSize: 30, isBold: true), - "SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), - ], - ), - "These charges are additional to the actual service charges. For heavy items the charges may vary.".toText(fontSize: 12, color: MyColors.lightTextColor), - 22.height, - ], - SizedBox( - width: double.infinity, - child: ShowFillButton( - maxHeight: 55, - title: "Next", - onPressed: () {}, - ), - ), - ], - ), - ).paddingOnly(bottom: 20) - ], - )).horPaddingMain(); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Book Appointment", - isRemoveBackButton: false, - isDrawerEnabled: false, - actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], - onBackButtonTapped: () => Navigator.pop(context), - ), - body: Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 21.height, - CustomAddButton( - onTap: () => {openTheAddServiceBottomSheet(context)}, - text: "Add Services", - icon: Container( - height: 24, - width: 24, - decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: const Icon(Icons.add, color: MyColors.white), - ), - ), - // 20.height, - // ListView.builder( - // physics: const NeverScrollableScrollPhysics(), - // shrinkWrap: true, - // itemCount: adVM.specialServiceCards.length, - // itemBuilder: (BuildContext context, int index) { - // SpecialServiceCard specialServicesCard = adVM.specialServiceCards[index]; - // return Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Column( - // children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Expanded( - // child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 16, isBold: true), - // ), - // Align( - // alignment: Alignment.topRight, - // child: MyAssets.closeWithOrangeBg.buildSvg( - // fit: BoxFit.fill, - // height: 30, - // width: 30, - // ), - // ).onPress(() => adVM.removeSpecialServiceCard(index)) - // ], - // ), - // Builder(builder: (context) { - // return Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // if (specialServicesCard.serviceSelectedId!.selectedId != 1 && specialServicesCard.serviceSelectedId!.selectedId != 3) ...[ - // // Row( - // // crossAxisAlignment: CrossAxisAlignment.start, - // // children: [ - // // "Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - // // (specialServicesCard.duration ?? "").toText(fontSize: 12, isBold: true).expand(), - // // ], - // // ), - // 8.height, - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // "Description: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - // (specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(), - // ], - // ), - // ], - // if (specialServicesCard.serviceSelectedId!.selectedId == 1 || specialServicesCard.serviceSelectedId!.selectedId == 3) ...[ - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // const Icon( - // weight: 2, - // Icons.location_on_outlined, - // color: MyColors.primaryColor, - // size: 17, - // ), - // "${specialServicesCard.duration} km".toText(fontSize: 10, color: MyColors.primaryColor), - // ], - // ), - // 8.height, - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // "Branch Address: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - // (specialServicesCard.address ?? "").toText(fontSize: 12, isBold: true).expand(), - // ], - // ), - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // "Appointment Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - // "${specialServicesCard.serviceDate} - ${specialServicesCard.serviceTime}".toText(fontSize: 12, isBold: true).expand(), - // ], - // ), - // ], - // 6.height, - // Row( - // crossAxisAlignment: CrossAxisAlignment.end, - // children: [ - // (specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true), - // 2.width, - // "SAR".toText(color: MyColors.lightTextColor, fontSize: 14), - // ], - // ), - // ], - // ); - // }), - // 3.height, - // const Divider(thickness: 1.5) - // ], - // ), - // 10.height, - // ], - // ); - // }, - // ), - ], - ); - }, - ).horPaddingMain()); - } -} diff --git a/lib/views/appointments/book_appointments_item_view.dart b/lib/views/appointments/book_appointments_item_view.dart new file mode 100644 index 0000000..cacb5c7 --- /dev/null +++ b/lib/views/appointments/book_appointments_item_view.dart @@ -0,0 +1,113 @@ +import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:car_customer_app/views/appointments/widgets/service_item_with_price_checkbox.dart'; +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:provider/provider.dart'; + +class BookAppointmentsItemView extends StatelessWidget { + const BookAppointmentsItemView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Select Services", + isRemoveBackButton: false, + isDrawerEnabled: false, + actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], + onBackButtonTapped: () => Navigator.pop(context), + ), + body: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 40, + width: double.infinity, + color: MyColors.darkTextColor, + alignment: Alignment.centerLeft, + child: "3 Items Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(), + ), + 16.height, + Column( + children: [ + "Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Change location or service: ".toText(fontSize: 14, isBold: true), + "Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor), + 5.width, + MyAssets.icEdit.buildSvg(width: 17), + ], + ).onPress(() {}), + 16.height, + Divider(), + ], + ).horPaddingMain(), + ListView.separated( + separatorBuilder: (BuildContext context, int index) => Divider(), + itemCount: 20, + itemBuilder: (BuildContext context, int index) { + return ServiceItemWithPriceCheckBox( + description: "Some description about the sub-services", + title: "Engine Check", + isSelected: true, + onSelection: (bool value) {}, + priceWidget: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + // TODO: This Price will be decided according to the service selected + 150.toString().toText(fontSize: 30, isBold: true), + "SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), + ], + ), + ); + }, + ).expand(), + Column( + children: [ + Divider( + height: 1, + thickness: 0.7, + ), + 16.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + txtColor: MyColors.black, + maxHeight: 55, + title: "Cancel", + onPressed: () {}, + backgroundColor: MyColors.greyButtonColor, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Next", + onPressed: () {}, + backgroundColor: MyColors.darkPrimaryColor, + ), + ), + ], + ).horPaddingMain(), + 16.height, + ], + ), + ], + ); + }, + )); + } +} diff --git a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart new file mode 100644 index 0000000..7ab24fc --- /dev/null +++ b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart @@ -0,0 +1,194 @@ +import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.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:provider/provider.dart'; + +class AppointmentServicePickBottomSheet extends StatelessWidget { + const AppointmentServicePickBottomSheet({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + AppointmentsVM appointmentsVM = context.watch(); + return SizedBox( + height: MediaQuery.of(context).size.height * 0.85, + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(8), + height: 8, + width: 60, + decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))), + ), + 12.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "Select Category".toText(fontSize: 24, isBold: true), + ], + ), + 30.height, + Expanded( + child: ListView( + children: [ + Builder( + builder: (context) { + List serviceCategories = []; + for (var element in appointmentsVM.providerCategories) { + if (!element.isSelected!) { + serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.categoryName ?? "", "")); + } + } + return DropdownField( + (DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), + list: serviceCategories, + hint: "Select Category", + dropdownValue: appointmentsVM.providerCategoryId.selectedId != -1 + ? DropValue(appointmentsVM.providerCategoryId.selectedId, appointmentsVM.providerCategoryId.selectedOption, "") + : null, + ); + }, + ), + if (appointmentsVM.isFetchingServices) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [const CircularProgressIndicator().paddingAll(10)], + ), + ] else if (appointmentsVM.providerServices.isNotEmpty) ...[ + 8.height, + Builder( + builder: (context) { + List serviceCategories = []; + for (var element in appointmentsVM.providerServices) { + if (!element.isSelected!) { + serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.id.toString(), "")); + } + } + return DropdownField( + (DropValue value) => appointmentsVM.updateProviderServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), + list: serviceCategories, + hint: "Select Services", + dropdownValue: appointmentsVM.providerServiceId.selectedId != -1 + ? DropValue(appointmentsVM.providerServiceId.selectedId, appointmentsVM.providerServiceId.selectedOption, "") + : null, + ); + }, + ), + ], + if (appointmentsVM.providerServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ + 16.height, + Row( + children: [ + "Select Service Location".toText( + fontSize: 16, + isBold: true, + color: MyColors.black, + ), + ], + ), + 8.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + isFilled: appointmentsVM.isHomeTapped, + maxHeight: 48, + title: "Home", + txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, + onPressed: () => appointmentsVM.updateIsHomeTapped(true), + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + isFilled: !appointmentsVM.isHomeTapped, + txtColor: !appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, + maxHeight: 48, + title: "Workshop", + onPressed: () => appointmentsVM.updateIsHomeTapped(false), + ), + ), + ], + ), + if (appointmentsVM.isHomeTapped) ...[ + 8.height, + TxtField( + hint: 'Pick Home Location', + errorValue: appointmentsVM.pickHomeLocationError, + value: appointmentsVM.pickedHomeLocation, + isNeedClickAll: true, + postfixData: Icons.location_on, + postFixDataColor: MyColors.darkTextColor, + onTap: () { + //TODO: open the place picked to pick the location and save it in provider. + appointmentsVM.updatePickedHomeLocation("PM58+F97, Al Olaya, Riyadh 12333"); + }, + ), + 14.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Icon( + Icons.warning, + color: MyColors.adPendingStatusColor, + size: 19, + ).paddingOnly(bottom: 2), + 3.width, + "Some services are not available on home location.".toText( + color: MyColors.adPendingStatusColor, + fontSize: 12, + isItalic: true, + ), + ], + ), + ] + ], + ], + ), + ), + SizedBox( + width: double.infinity, + child: Column( + children: [ + if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[ + const Divider(thickness: 1, height: 1), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + // TODO: This Price will be decided according to the service selected + 150.toString().toText(fontSize: 30, isBold: true), + "SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), + ], + ), + "These charges are additional to the actual service charges. For heavy items the charges may vary.".toText(fontSize: 12, color: MyColors.lightTextColor), + 22.height, + ], + SizedBox( + width: double.infinity, + child: ShowFillButton( + maxHeight: 55, + backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, + title: "Next", + onPressed: () { + bool isValidated = appointmentsVM.isServiceSelectionValidated(); + if (isValidated) { + navigateWithName(context, AppRoutes.bookAppointmentsItemView); + } + }, + ), + ), + ], + ), + ).paddingOnly(bottom: 20) + ], + )).horPaddingMain(); + } +} diff --git a/lib/views/appointments/widgets/service_item_with_price_checkbox.dart b/lib/views/appointments/widgets/service_item_with_price_checkbox.dart new file mode 100644 index 0000000..f8269c6 --- /dev/null +++ b/lib/views/appointments/widgets/service_item_with_price_checkbox.dart @@ -0,0 +1,51 @@ +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/widgets/extensions/extensions_widget.dart'; + +class ServiceItemWithPriceCheckBox extends StatelessWidget { + final bool isSelected; + final String title, description; + final Widget priceWidget; + + final Function(bool) onSelection; + + const ServiceItemWithPriceCheckBox({ + required this.isSelected, + required this.title, + required this.description, + this.priceWidget = const SizedBox(), + required this.onSelection, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Checkbox( + value: isSelected, + onChanged: (bool? v) { + onSelection(v ?? false); + }, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + title.toText(fontSize: 16, isBold: true).paddingOnly(top: 10), + description.toText(fontSize: 12, color: MyColors.lightTextColor), + priceWidget, + ], + ), + ), + ], + ), + ); + } +} From 3390112aa3b3d0184e9f594155a3158e42be08db Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Wed, 14 Jun 2023 15:20:49 +0300 Subject: [PATCH 2/4] test commit to GitTea --- lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index f518977..3bef3f4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,6 +26,8 @@ import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; import 'package:sizer/sizer.dart'; + +//test commit Future main() async { WidgetsFlutterBinding.ensureInitialized(); CustomerDependencies.addDependencies(); From 3f0178e1cd04c4509c319d9df182a3d7e6a81c33 Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Thu, 15 Jun 2023 17:23:29 +0300 Subject: [PATCH 3/4] Completed the new design for the Appointment Flow --- lib/config/customer_routes.dart | 2 + .../appointment_services_list_view.dart | 103 ++++++- .../appointments/review_appointment_view.dart | 265 ++++++++++++++++++ .../dashboard/fragments/ads_fragment.dart | 4 +- 4 files changed, 371 insertions(+), 3 deletions(-) create mode 100644 lib/views/appointments/review_appointment_view.dart diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index bcf7484..bcbb4e0 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -2,6 +2,7 @@ import 'package:car_customer_app/views/appointments/appointment_detail_view.dart import 'package:car_customer_app/views/appointments/appointment_services_list_view.dart'; import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart'; +import 'package:car_customer_app/views/appointments/review_appointment_view.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/config/routes.dart'; @@ -20,6 +21,7 @@ class CustomerAppRoutes { AppRoutes.createAdView: (context) => CreateAdView(), AppRoutes.bookAppointmenServicesView: (context) => AppointmentServicesListView(), AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), + AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), }; } diff --git a/lib/views/appointments/appointment_services_list_view.dart b/lib/views/appointments/appointment_services_list_view.dart index c2aae69..3d6355c 100644 --- a/lib/views/appointments/appointment_services_list_view.dart +++ b/lib/views/appointments/appointment_services_list_view.dart @@ -2,12 +2,16 @@ import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/views/advertisement/custom_add_button.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/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -48,6 +52,73 @@ class AppointmentServicesListView extends StatelessWidget { TimeSlotModel(isSelected: false, slotId: 19, slot: "29:00"), ]; + void priceBreakDownClicked(BuildContext context) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return InfoBottomSheet( + title: "Charges Breakdown", + description: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Services".toText(fontSize: 16, isBold: true), + Column( + children: List.generate( + 5, + (index) => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Gear Kit".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "200 SAR".toText(fontSize: 12, isBold: true), + ], + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "1149 SAR".toText(fontSize: 16, isBold: true), + ], + ), + 20.height, + "Home Location".toText(fontSize: 16, isBold: true), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "5 x 10".toText(fontSize: 12, isBold: true), + ], + ), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "50 SAR".toText(fontSize: 16, isBold: true), + ], + ), + 30.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total Amount ".toText(fontSize: 16, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "120".toText(fontSize: 29, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + ], + ) + ], + ), + 30.height, + ], + )); + }); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -125,8 +196,12 @@ class AppointmentServicesListView extends StatelessWidget { "120".toText(fontSize: 29, isBold: true), 2.width, "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + Icon( + Icons.arrow_drop_down, + size: 30, + ) ], - ), + ).onPress(() => priceBreakDownClicked(context)), ], if (true) ...[ 8.height, @@ -146,7 +221,31 @@ class AppointmentServicesListView extends StatelessWidget { ], ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); }, - ).expand() + ).expand(), + Row( + children: [ + Expanded( + child: ShowFillButton( + txtColor: MyColors.black, + maxHeight: 55, + title: "Cancel", + onPressed: () {}, + backgroundColor: MyColors.greyButtonColor, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Review", + onPressed: () { + navigateWithName(context, AppRoutes.reviewAppointmentView); + }, + backgroundColor: MyColors.darkPrimaryColor, + ), + ) + ], + ).paddingAll(21) ], ); }, diff --git a/lib/views/appointments/review_appointment_view.dart b/lib/views/appointments/review_appointment_view.dart new file mode 100644 index 0000000..96c8a88 --- /dev/null +++ b/lib/views/appointments/review_appointment_view.dart @@ -0,0 +1,265 @@ +import 'package:easy_localization/easy_localization.dart'; +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/generated/locale_keys.g.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'; + +class ReviewAppointment extends StatelessWidget { + const ReviewAppointment({Key? key}) : super(key: key); + + Widget buildBranchInfoCard({ + required String branchImageUrl, + required String branchName, + required String branchRatings, + required String branchLocation, + }) { + return Padding( + padding: const EdgeInsets.only( + bottom: 10, + left: 21, + right: 21, + ), + child: Row( + children: [ + Image.asset( + branchImageUrl, + width: 80, + height: 60, + fit: BoxFit.cover, + ), + 12.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + branchName.toText(fontSize: 16, isBold: true), + Row( + children: [ + LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12), + 2.width, + ":$branchLocation".toText(fontSize: 12), + ], + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + branchRatings.toText( + isUnderLine: true, + isBold: true, + fontSize: 12, + ), + 2.width, + MyAssets.starIcon.buildSvg(width: 12), + ], + ), + ], + ), + ], + ), + ), + ], + ).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12)); + } + + Widget buildServicesSubSection({required String title, required List itemList}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title.toText(fontSize: 16, isBold: true), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate( + itemList.length, + (index) => itemList[index].toText( + fontSize: 12, + color: MyColors.lightTextColor, + isBold: true, + )), + ), + ], + ).paddingOnly(bottom: 14); + } + + Widget buildServicesInfoCard() { + return SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate( + 2, + (index) => buildServicesSubSection( + title: "Mechanic", + itemList: [ + "Engine Check : 450 SAR", + "Gear Check : 700 SAR", + "Gear Check : 700 SAR", + "Gear Check : 700 SAR", + ], + ), + ), + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.symmetric(horizontal: 21)), + ); + } + + Widget buildTimeAndLocationInfoCard() { + return SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Time & Location".toText(fontSize: 16, isBold: true), + 3.height, + Row(children: [ + "Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "2nd Feb, 2023 at 09:30 AM".toText(fontSize: 12, isBold: true), + ]), + Row(children: [ + "Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true), + ]), + ], + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10)), + ); + } + + Widget buildChargesBreakDown() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Services".toText(fontSize: 16, isBold: true), + Column( + children: List.generate( + 5, + (index) => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Gear Kit".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "200 SAR".toText(fontSize: 12, isBold: true), + ], + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "1149 SAR".toText(fontSize: 16, isBold: true), + ], + ), + 10.height, + Divider( + thickness: 0.7, + ), + "Home Location".toText(fontSize: 16, isBold: true), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "5 x 10".toText(fontSize: 12, isBold: true), + ], + ), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "50 SAR".toText(fontSize: 16, isBold: true), + ], + ), + 10.height, + Divider( + thickness: 0.7, + ), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total Amount ".toText(fontSize: 16, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "120".toText(fontSize: 29, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + ], + ) + ], + ), + 10.height, + ], + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21)); + } + + Widget buildNextButtonFooter() { + return Container( + height: 90, + color: MyColors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Divider(thickness: 0.7, height: 3), + 10.height, + SizedBox( + width: double.infinity, + child: ShowFillButton( + maxHeight: 55, + backgroundColor: MyColors.primaryColor, + title: "Book Appointment", + onPressed: () {}, + ).paddingOnly(bottom: 12, left: 21, right: 21), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Review Appointment", + isRemoveBackButton: false, + isDrawerEnabled: false, + actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], + onBackButtonTapped: () => Navigator.pop(context), + ), + body: Stack( + alignment: Alignment.bottomCenter, + children: [ + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildBranchInfoCard( + branchImageUrl: MyAssets.bnCar, + branchLocation: " 3km", + branchName: "Al Ahmed Maintenance", + branchRatings: "4.9", + ), + buildServicesInfoCard(), + buildTimeAndLocationInfoCard(), + buildChargesBreakDown(), + ], + ), + ), + buildNextButtonFooter(), + ], + ), + ); + } +} diff --git a/lib/views/dashboard/fragments/ads_fragment.dart b/lib/views/dashboard/fragments/ads_fragment.dart index d13952c..3201ffa 100644 --- a/lib/views/dashboard/fragments/ads_fragment.dart +++ b/lib/views/dashboard/fragments/ads_fragment.dart @@ -103,7 +103,9 @@ class AdsFragment extends StatelessWidget { ), floatingActionButton: FloatingActionButton( onPressed: () { - context.read().getVehicleTypes(); + if (context.read().vehicleTypes.isEmpty) { + context.read().getVehicleTypes(); + } navigateWithName(context, AppRoutes.createAdView); }, From 8bc13dff3427dd9689984d888ea1ba673f421425 Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Tue, 20 Jun 2023 15:55:55 +0300 Subject: [PATCH 4/4] Updated the New Models --- lib/config/customer_dependencies.dart | 2 +- lib/config/customer_routes.dart | 4 +- lib/main.dart | 8 +- lib/repositories/provider_repo.dart | 37 +++--- lib/view_models/appointments_view_model.dart | 114 +++++++++++++----- lib/view_models/providers_view_model.dart | 85 +++---------- ...appointment_service_pick_bottom_sheet.dart | 14 +-- lib/views/dashboard/dashboard_page.dart | 8 +- .../fragments/appointments_fragment.dart | 6 +- .../fragments/branches_fragment.dart | 60 +++++---- .../dashboard/fragments/home_fragment.dart | 2 +- .../fragments/providers_fragment.dart | 7 +- lib/views/provider/branch_detail_page.dart | 49 ++++---- lib/views/provider/provider_profile_page.dart | 12 +- .../provider/sheet/items_list_sheet.dart | 13 +- pubspec.yaml | 2 +- 16 files changed, 212 insertions(+), 211 deletions(-) diff --git a/lib/config/customer_dependencies.dart b/lib/config/customer_dependencies.dart index 3debdff..b41d76a 100644 --- a/lib/config/customer_dependencies.dart +++ b/lib/config/customer_dependencies.dart @@ -4,7 +4,7 @@ import 'package:mc_common_app/config/dependencies.dart'; class CustomerDependencies { static void addDependencies() { AppDependencies.addDependencies(); - injector.registerSingleton(() => ProviderRepoImp()); + injector.registerSingleton(() => BranchRepoImp()); } } diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index b524a29..b90265b 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -10,7 +10,7 @@ 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'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; -import 'package:mc_common_app/models/services/branch_model.dart'; +import 'package:mc_common_app/models/branch_models/branch_detail_model.dart'; import 'package:mc_common_app/views/advertisement/ads_detail_view.dart'; import 'package:mc_common_app/views/advertisement/create_ad_view.dart'; import 'package:mc_common_app/views/payments/payment_methods_view.dart'; @@ -26,7 +26,7 @@ class CustomerAppRoutes { AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), - AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchModel: ModalRoute.of(context)!.settings.arguments as BranchModel), + AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel), AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), }; } diff --git a/lib/main.dart b/lib/main.dart index ae0ad10..d258ca2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -55,16 +55,10 @@ Future main() async { adsRepo: injector.get(), ), ), - ChangeNotifierProvider( - create: (_) => ProvidersVM( - commonServices: injector.get(), - commonRepo: injector.get(), - providerRepo: injector.get(), - ), - ), ChangeNotifierProvider( create: (_) => AppointmentsVM( commonServices: injector.get(), + branchRepo: injector.get(), commonRepo: injector.get(), ), ), diff --git a/lib/repositories/provider_repo.dart b/lib/repositories/provider_repo.dart index d92a66d..dc057f3 100644 --- a/lib/repositories/provider_repo.dart +++ b/lib/repositories/provider_repo.dart @@ -1,33 +1,38 @@ import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:mc_common_app/models/model/provider_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/services/near_branch_model.dart'; -import 'package:http/http.dart' as http; +import 'package:flutter/cupertino.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/branch_models/branch_detail_model.dart'; +import 'package:mc_common_app/models/generic_resp_model.dart'; +import 'package:mc_common_app/models/model/provider_model.dart'; +import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:flutter/cupertino.dart'; - -abstract class ProviderRepo { - Future getAllNearBranchAndServices(); +abstract class BranchRepo { + Future> getAllNearBranchAndServices(); Future getServiceItems(int serviceId); Future getBranchAndServices(int providerId); } -class ProviderRepoImp implements ProviderRepo { +class BranchRepoImp implements BranchRepo { + ApiClient apiClient = injector.get(); + AppState appState = injector.get(); + @override - Future getAllNearBranchAndServices() async { - // var postParams = {"serviceProviderID": AppState().getUser.data?.userInfo?.providerId.toString() ?? ""}; - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().getJsonForObject((json) => NearBrancheModel.fromJson(json), ApiConsts.GetAllNearBranches, token: t); + Future> getAllNearBranchAndServices() async { + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.GetAllNearBranches, + token: appState.getUser.data!.accessToken, + ); + + List branches = List.generate(adsGenericModel.data.length, (index) => BranchDetailModel.fromJson(adsGenericModel.data[index])); + + return branches; } @override diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index 94d836c..90afeb1 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,17 +1,71 @@ -import 'package:flutter/cupertino.dart'; +import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; +import 'package:mc_common_app/models/branch_models/branch_detail_model.dart'; import 'package:mc_common_app/models/provider_category_model.dart'; -import 'package:mc_common_app/models/provider_service_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/view_models/base_view_model.dart'; +import 'package:mc_common_app/models/services/item_model.dart'; -class AppointmentsVM extends ChangeNotifier { + +class AppointmentsVM extends BaseVM { final CommonRepo commonRepo; + final BranchRepo branchRepo; final CommonAppServices commonServices; - AppointmentsVM({required this.commonServices, required this.commonRepo}); + AppointmentsVM({required this.commonServices, required this.branchRepo, required this.commonRepo}); + + List providersFilterOptions = []; + List nearbyBranchesList = []; + ItemModel? serviceItems; + ProviderModel? providerModel; + + populateProvidersFilterList() { + providersFilterOptions.clear(); + providersFilterOptions = [ + FilterListModel(title: "All Branches", 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), + ]; + notifyListeners(); + } + + applyFilterOnProviders({required int index}) { + if (providersFilterOptions.isEmpty) return; + for (var value in providersFilterOptions) { + value.isSelected = false; + } + providersFilterOptions[index].isSelected = true; + notifyListeners(); + } + + //Create new branch + getAllNearBranches({bool isNeedToRebuild = false}) async { + //TODO: needs to lat,long into API + nearbyBranchesList.clear(); + if (isNeedToRebuild) setState(ViewState.busy); + nearbyBranchesList = await branchRepo.getAllNearBranchAndServices(); + setState(ViewState.idle); + } + + Future getServiceItems(int serviceId) async { + serviceItems = null; + serviceItems = await branchRepo.getServiceItems(serviceId); + setState(ViewState.idle); + return serviceItems; + } + + getBranchAndServices(int providerId) async { + providerModel = null; + providerModel = await branchRepo.getBranchAndServices(providerId); + setState(ViewState.idle); + } bool isFetchingLists = false; @@ -20,7 +74,7 @@ class AppointmentsVM extends ChangeNotifier { bool isFetchingServices = false; - List providerCategories = []; + List branchCategories = []; bool isHomeTapped = false; @@ -47,27 +101,48 @@ class AppointmentsVM extends ChangeNotifier { void updateProviderCategoryId(SelectionModel id) async { providerCategoryId = id; - await getProviderServices(id.selectedId); + await getBranchServices(id.selectedId); notifyListeners(); } - List providerServices = []; + List branchServices = []; - SelectionModel providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + SelectionModel branchServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateProviderServiceId(SelectionModel id) async { - providerServiceId = id; + branchServiceId = id; notifyListeners(); } - void getProviderCategories() async { + void getBranchCategories() async { notifyListeners(); - providerCategories = await commonRepo.getProviderServiceCategories(); + branchCategories = await commonRepo.getProviderServiceCategories(); notifyListeners(); } + getBranchServices(int categoryId) async { + branchServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + isHomeTapped = false; + pickedHomeLocation = ""; + pickHomeLocationError = ""; + if (categoryId != -1) { + isFetchingServices = true; + notifyListeners(); + branchServices = getFilteredBranchServices(categoryId: categoryId, branchId: 6); + isFetchingServices = false; + + notifyListeners(); + } + } + + List getFilteredBranchServices({required int branchId, required int categoryId}) { + + // List filteredServices = nearbyBranchesList.where((element) => element) + return []; + } + bool isServiceSelectionValidated() { - if (providerServiceId.selectedId == -1) { + if (branchServiceId.selectedId == -1) { return false; } @@ -80,21 +155,6 @@ class AppointmentsVM extends ChangeNotifier { return true; } - getProviderServices(int categoryId) async { - providerServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - isHomeTapped = false; - pickedHomeLocation = ""; - pickHomeLocationError = ""; - if (categoryId != -1) { - isFetchingServices = true; - notifyListeners(); - providerServices = await commonRepo.getProviderServices(categoryId: categoryId); - isFetchingServices = false; - - notifyListeners(); - } - } - populateAppointmentsFilterList() { appointmentsFilterOptions.clear(); appointmentsFilterOptions = [ diff --git a/lib/view_models/providers_view_model.dart b/lib/view_models/providers_view_model.dart index 568f713..6083eef 100644 --- a/lib/view_models/providers_view_model.dart +++ b/lib/view_models/providers_view_model.dart @@ -1,67 +1,18 @@ -import 'package:mc_common_app/models/model/provider_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/services/near_branch_model.dart'; -import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:flutter/cupertino.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/view_models/base_view_model.dart'; - -class ProvidersVM extends BaseVM { - final CommonRepo commonRepo; - final CommonAppServices commonServices; - final ProviderRepo providerRepo; - - ProvidersVM({required this.commonServices, required this.commonRepo, required this.providerRepo}); - - List providersFilterOptions = []; - NearBrancheModel? branches; - ItemModel? serviceItems; - ProviderModel? providerModel; - - populateProvidersFilterList() { - 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), - ]; - notifyListeners(); - } - - applyFilterOnProviders({required int index}) { - if (providersFilterOptions.isEmpty) return; - for (var value in providersFilterOptions) { - value.isSelected = false; - } - providersFilterOptions[index].isSelected = true; - notifyListeners(); - } - - //Create new branch - getAllNearBranches({bool isNeedToRebuild = false}) async { - //TODO: needs to lat,long into API - branches = null; - if (isNeedToRebuild) setState(ViewState.busy); - branches = await providerRepo.getAllNearBranchAndServices(); - setState(ViewState.idle); - } - - Future getServiceItems(int serviceId) async { - serviceItems = null; - serviceItems = await providerRepo.getServiceItems(serviceId); - setState(ViewState.idle); - return serviceItems; - } - - getBranchAndServices(int providerId) async { - providerModel = null; - providerModel = await providerRepo.getBranchAndServices(providerId); - setState(ViewState.idle); - } -} +// import 'package:car_customer_app/repositories/provider_repo.dart'; +// import 'package:mc_common_app/models/branch_models/branch_detail_model.dart'; +// import 'package:mc_common_app/models/model/provider_model.dart'; +// import 'package:mc_common_app/models/services/item_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/view_models/base_view_model.dart'; + +// class ProvidersVM extends BaseVM { +// final CommonRepo commonRepo; +// final CommonAppServices commonServices; +// final ProviderRepo providerRepo; +// +// ProvidersVM({required this.commonServices, required this.commonRepo, required this.providerRepo}); +// +// } diff --git a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart index 7ab24fc..6ea7081 100644 --- a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart +++ b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart @@ -42,7 +42,7 @@ class AppointmentServicePickBottomSheet extends StatelessWidget { Builder( builder: (context) { List serviceCategories = []; - for (var element in appointmentsVM.providerCategories) { + for (var element in appointmentsVM.branchCategories) { if (!element.isSelected!) { serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.categoryName ?? "", "")); } @@ -62,28 +62,28 @@ class AppointmentServicePickBottomSheet extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [const CircularProgressIndicator().paddingAll(10)], ), - ] else if (appointmentsVM.providerServices.isNotEmpty) ...[ + ] else if (appointmentsVM.branchServices.isNotEmpty) ...[ 8.height, Builder( builder: (context) { List serviceCategories = []; - for (var element in appointmentsVM.providerServices) { + for (var element in appointmentsVM.branchServices) { if (!element.isSelected!) { - serviceCategories.add(DropValue(element.id?.toInt() ?? 0, element.id.toString(), "")); + serviceCategories.add(DropValue(element.providerBranchServiceID ?? 0, element.providerBranchServiceID.toString(), "")); } } return DropdownField( (DropValue value) => appointmentsVM.updateProviderServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), list: serviceCategories, hint: "Select Services", - dropdownValue: appointmentsVM.providerServiceId.selectedId != -1 - ? DropValue(appointmentsVM.providerServiceId.selectedId, appointmentsVM.providerServiceId.selectedOption, "") + dropdownValue: appointmentsVM.branchServiceId.selectedId != -1 + ? DropValue(appointmentsVM.branchServiceId.selectedId, appointmentsVM.branchServiceId.selectedOption, "") : null, ); }, ), ], - if (appointmentsVM.providerServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ + if (appointmentsVM.branchServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ 16.height, Row( children: [ diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index 1c9fa86..8b55571 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -2,11 +2,9 @@ import 'dart:async'; 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/providers_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'; -import 'package:car_customer_app/views/dashboard/fragments/providers_fragment.dart'; import 'package:car_customer_app/views/dashboard/fragments/settings_fragment.dart'; import 'package:car_customer_app/views/dashboard/widgets/bottom_nav_bar.dart'; import 'package:car_customer_app/views/dashboard/widgets/drawer_widget.dart'; @@ -36,9 +34,9 @@ class _DashboardPageState extends State { fetchUsername(); scheduleMicrotask(() { context.read().populateAppointmentsFilterList(); - context.read().populateProvidersFilterList(); + context.read().populateProvidersFilterList(); context.read().populateAdsFilterList(); - context.read().getAllNearBranches(); + context.read().getAllNearBranches(); _onRefresh(); }); } @@ -69,7 +67,7 @@ class _DashboardPageState extends State { String getPageTitle(int index) { if (index == 0) { - return "Branchs"; + return "Branches"; } if (index == 1) { return "Appointments"; diff --git a/lib/views/dashboard/fragments/appointments_fragment.dart b/lib/views/dashboard/fragments/appointments_fragment.dart index 137ae1e..aff1704 100644 --- a/lib/views/dashboard/fragments/appointments_fragment.dart +++ b/lib/views/dashboard/fragments/appointments_fragment.dart @@ -41,7 +41,11 @@ class AppointmentsFragment extends StatelessWidget { itemCount: appointmentsVM.myAppointments.length, itemBuilder: (BuildContext context, int index) { return BuildAppointmentContainerForCustomer( - onTapped: () => navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentsVM.myAppointments[index]), + onTapped: () => navigateWithName( + context, + AppRoutes.appointmentDetailView, + arguments: appointmentsVM.myAppointments[index], + ), appointmentListModel: appointmentsVM.myAppointments[index], ); }, diff --git a/lib/views/dashboard/fragments/branches_fragment.dart b/lib/views/dashboard/fragments/branches_fragment.dart index d0ab34c..f94231e 100644 --- a/lib/views/dashboard/fragments/branches_fragment.dart +++ b/lib/views/dashboard/fragments/branches_fragment.dart @@ -1,17 +1,16 @@ -import 'package:car_customer_app/view_models/providers_view_model.dart'; +import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:flutter/material.dart'; - import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/branch_models/branch_detail_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:mc_common_app/widgets/common_widgets/provider_details_card.dart'; import 'package:provider/provider.dart'; -import 'package:easy_localization/easy_localization.dart'; class BranchesFragment extends StatelessWidget { const BranchesFragment({Key? key}) : super(key: key); @@ -23,7 +22,7 @@ class BranchesFragment extends StatelessWidget { width: double.infinity, height: double.infinity, child: Consumer( - builder: (BuildContext context, ProvidersVM providersVM, Widget? child) { + builder: (BuildContext context, AppointmentsVM providersVM, Widget? child) { return Column( children: [ 16.height, @@ -35,41 +34,40 @@ class BranchesFragment extends StatelessWidget { Expanded( child: RefreshIndicator( onRefresh: () async { - context.read().getAllNearBranches(isNeedToRebuild: true); + context.read().getAllNearBranches(isNeedToRebuild: true); }, child: SingleChildScrollView( child: Container( width: double.infinity, height: MediaQuery.of(context).size.height / 1.37, - child: Consumer( - builder: (context, model, _) { - if (model.state == ViewState.busy) { + child: Consumer( + builder: (context, viewModel, _) { + if (viewModel.state == ViewState.busy) { return const Center(child: CircularProgressIndicator()); } else { - return model.branches?.data == null - ? const Center(child: Text("No Branch Found")) - : model.branches!.data!.isEmpty - ? Center(child: Text(LocaleKeys.no_branch.tr())) - : ListView.separated( - itemBuilder: (context, index) { - return ProviderDetailsCard( - onCardTapped: () { - navigateWithName(context, AppRoutes.branchDetailPage, arguments: model.branches!.data![index]); - }, - providerImageUrl: MyAssets.bnCar, - title: model.branches!.data![index].branchName ?? "", - providerLocation: model.branches!.data![index].distanceKm.toString() + " KM", - providerName: model.branches!.data![index].serviceProviderName ?? "", - providerRatings: "4.9", - items: model.branches!.data![index].branchServices, - ); - }, - separatorBuilder: (context, index) { - return 12.height; + return viewModel.nearbyBranchesList.isEmpty + ? Center(child: "No Branches to show.".toText(fontSize: 16, color: MyColors.lightTextColor)) + : ListView.separated( + itemCount: viewModel.nearbyBranchesList.length, + itemBuilder: (context, index) { + BranchDetailModel branchDetailModel = viewModel.nearbyBranchesList[index]; + return ProviderDetailsCard( + onCardTapped: () { + navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel); }, - itemCount: model.branches!.data!.length, - padding: const EdgeInsets.all(12), + providerImageUrl: MyAssets.bnCar, + title: branchDetailModel.branchName ?? "", + providerLocation: branchDetailModel.distanceKM.toString() + " KM", + providerName: branchDetailModel.serviceProviderName ?? "", + providerRatings: "4.9", + items: branchDetailModel.branchServices, ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + padding: const EdgeInsets.all(12), + ); } }, ), diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index c7c4d6b..158416e 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -43,7 +43,7 @@ class HomeFragment extends StatelessWidget { onSubtitleTapped: () { print("value: ${AppState().getUser.data!.accessToken}"); context.read().onNavbarTapped(0); - context.read().applyFilterOnProviders(index: 0); + context.read().applyFilterOnProviders(index: 0); }).horPaddingMain(), const ServiceProviderWidget().horPaddingMain(), Consumer( diff --git a/lib/views/dashboard/fragments/providers_fragment.dart b/lib/views/dashboard/fragments/providers_fragment.dart index 09e6dab..b749bd0 100644 --- a/lib/views/dashboard/fragments/providers_fragment.dart +++ b/lib/views/dashboard/fragments/providers_fragment.dart @@ -1,5 +1,4 @@ import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/view_models/providers_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; @@ -20,7 +19,7 @@ class ProvidersFragment extends StatelessWidget { width: double.infinity, height: double.infinity, child: Consumer( - builder: (BuildContext context, ProvidersVM providersVM, Widget? child) { + builder: (BuildContext context, AppointmentsVM providersVM, Widget? child) { return Column( children: [ 16.height, @@ -37,8 +36,8 @@ class ProvidersFragment extends StatelessWidget { itemBuilder: (BuildContext context, int index) { return ProviderDetailsCard( onCardTapped: () { - if (context.read().providerCategories.isEmpty) { - context.read().getProviderCategories(); + if (context.read().branchCategories.isEmpty) { + context.read().getBranchCategories(); } navigateWithName(context, AppRoutes.bookAppointmenServicesView); }, diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index f9432ae..e5973cb 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -1,13 +1,12 @@ import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; -import 'package:mc_common_app/models/services/branch_model.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; +import 'package:mc_common_app/models/branch_models/branch_detail_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/widgets/bottom_sheet.dart'; @@ -16,9 +15,9 @@ import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class BranchDetailPage extends StatefulWidget { - BranchModel branchModel; + final BranchDetailModel branchDetailModel; - BranchDetailPage({required this.branchModel}); + BranchDetailPage({required this.branchDetailModel}); @override State createState() => _BranchDetailPageState(); @@ -29,7 +28,7 @@ class _BranchDetailPageState extends State { void initState() { // TODO: implement initState super.initState(); - if (widget.branchModel.branchServices!.length > 0) widget.branchModel.branchServices?.first.isExpanded = true; + if (widget.branchDetailModel.branchServices!.length > 0) widget.branchDetailModel.branchServices?.first.isExpanded = true; } @override @@ -52,7 +51,7 @@ class _BranchDetailPageState extends State { children: [ Image.asset(MyAssets.bnCar), 12.height, - "${widget.branchModel.branchName} | ${widget.branchModel.serviceProviderName}".toString().toText( + "${widget.branchDetailModel.branchName} | ${widget.branchDetailModel.serviceProviderName}".toString().toText( fontSize: 16, isBold: true, ), @@ -60,14 +59,14 @@ class _BranchDetailPageState extends State { children: [ (LocaleKeys.location.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12), 4.width, - (widget.branchModel.distanceKm.toString() + " km").toText(fontSize: 12, isBold: true), + (widget.branchDetailModel.distanceKM.toString() + " km").toText(fontSize: 12, isBold: true), ], ), Row( children: [ ("Time" + ":").toText(color: MyColors.lightTextColor, fontSize: 12), 4.width, - "${widget.branchModel.openTime} - ${widget.branchModel.closeTime}".toText(fontSize: 12, isBold: true), + "${widget.branchDetailModel.openTime} - ${widget.branchDetailModel.closeTime}".toText(fontSize: 12, isBold: true), ], ), 2.height, @@ -123,7 +122,7 @@ class _BranchDetailPageState extends State { ) .onPress( () { - navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchModel.serviceProviderId); + navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderID); }, ), ], @@ -134,7 +133,7 @@ class _BranchDetailPageState extends State { color: MyColors.lightTextColor, isBold: true, ), - if (widget.branchModel.branchServices!.length == 0) "No Services Available".toText(fontSize: 12, isBold: true), + if (widget.branchDetailModel.branchServices!.length == 0) "No Services Available".toText(fontSize: 12, isBold: true), showServicesList(), ], ).toWhiteContainer( @@ -150,7 +149,9 @@ class _BranchDetailPageState extends State { title: "Book Appointment", maxWidth: double.infinity, margin: EdgeInsets.all(21), - onPressed: () {}, + onPressed: () { + navigateWithName(context, AppRoutes.bookAppointmenServicesView); + }, ).toContainer( paddingAll: 0, backgroundColor: Colors.white, @@ -165,7 +166,7 @@ class _BranchDetailPageState extends State { itemBuilder: (context, index) { return ExpansionTile( tilePadding: EdgeInsets.zero, - title: (widget.branchModel.branchServices![index].serviceDescription ?? "").toText( + title: (widget.branchDetailModel.branchServices![index].serviceDescription ?? "").toText( fontSize: 16, isBold: true, ), @@ -173,11 +174,11 @@ class _BranchDetailPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - showItem("Allowing home service:", (widget.branchModel.branchServices![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), - showItem("Home service range", widget.branchModel.branchServices![index].customerLocationRange.toString() + "KM"), - showItem("Charges per KM", widget.branchModel.branchServices![index].customerLocationRange.toString() + "SAR"), + showItem("Allowing home service:", (widget.branchDetailModel.branchServices![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Home service range", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"), + showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"), 8.height, - (widget.branchModel.branchServices![index].itemsCount.toString() + "+ items").toText( + (widget.branchDetailModel.branchServices![index].itemsCount.toString() + "+ items").toText( fontSize: 12, isBold: true, color: MyColors.primaryColor, @@ -186,26 +187,24 @@ class _BranchDetailPageState extends State { 20.height, ], ).onPress(() { - showMyBottomSheet(context, child: ItemsListSheet(widget.branchModel.branchServices![index].providerBranchServiceId ?? 0)); + showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].providerBranchServiceID ?? 0)); }), ], onExpansionChanged: (value) { setState(() { - widget.branchModel.branchServices![index].isExpanded = value; + widget.branchDetailModel.branchServices![index].isExpanded = value; }); }, backgroundColor: Colors.transparent, collapsedBackgroundColor: Colors.transparent, - initiallyExpanded: widget.branchModel.branchServices![index].isExpanded, - trailing: widget.branchModel.branchServices![index].isExpanded ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down), + initiallyExpanded: widget.branchDetailModel.branchServices![index].isExpanded!, + trailing: widget.branchDetailModel.branchServices![index].isExpanded! ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down), ); }, separatorBuilder: (context, index) { - return Divider( - height: 1, - ); + return Divider(height: 1); }, - itemCount: widget.branchModel.branchServices!.length, + itemCount: widget.branchDetailModel.branchServices!.length, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, ); diff --git a/lib/views/provider/provider_profile_page.dart b/lib/views/provider/provider_profile_page.dart index 84d041f..ac350bb 100644 --- a/lib/views/provider/provider_profile_page.dart +++ b/lib/views/provider/provider_profile_page.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/providers_view_model.dart'; +import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -10,7 +10,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; class ProviderProfilePage extends StatefulWidget { - int providerId; + final int providerId; ProviderProfilePage({required this.providerId}); @@ -22,20 +22,18 @@ class _ProviderProfilePageState extends State { @override void initState() { super.initState(); - context.read().getBranchAndServices(widget.providerId ?? 0); + context.read().getBranchAndServices(widget.providerId); } @override Widget build(BuildContext context) { return Scaffold( - appBar: CustomAppBar( - title: "Provider Details", - ), + appBar: CustomAppBar(title: "Provider Details"), body: Container( width: double.infinity, height: double.infinity, padding: EdgeInsets.all(21), - child: Consumer( + child: Consumer( builder: (context, model, _) { return model.providerModel == null ? const Center(child: CircularProgressIndicator()) diff --git a/lib/views/provider/sheet/items_list_sheet.dart b/lib/views/provider/sheet/items_list_sheet.dart index 63a8fbf..7870b53 100644 --- a/lib/views/provider/sheet/items_list_sheet.dart +++ b/lib/views/provider/sheet/items_list_sheet.dart @@ -1,19 +1,14 @@ -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:car_customer_app/view_models/appointments_view_model.dart'; 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/utils/enums.dart'; import 'package:mc_common_app/widgets/empty_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; -import '../../../view_models/providers_view_model.dart'; - class ItemsListSheet extends StatefulWidget { - int serviceId; + final int serviceId; ItemsListSheet(this.serviceId); @@ -25,14 +20,14 @@ class _ItemsListSheetState extends State { @override void initState() { super.initState(); - context.read().getServiceItems(widget.serviceId ?? 0); + context.read().getServiceItems(widget.serviceId); } @override Widget build(BuildContext context) { return SizedBox( height: MediaQuery.of(context).size.height / 1.2, - child: Consumer( + child: Consumer( builder: (context, model, _) { return model.serviceItems == null ? const Center(child: CircularProgressIndicator()) diff --git a/pubspec.yaml b/pubspec.yaml index 46981f4..1c5a0d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: cupertino_icons: ^1.0.2 mc_common_app: - path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app + path: D:/Development/car_common_app dev_dependencies: flutter_test: