From 237911d71131f77ec192d0ecd4c4094df3c4b7c4 Mon Sep 17 00:00:00 2001 From: "mirza.shafique" Date: Wed, 14 Jun 2023 14:39:25 +0300 Subject: [PATCH 1/3] Common Setup 1 --- lib/config/customer_dependencies.dart | 2 + lib/main.dart | 2 + lib/repositories/provider_repo.dart | 30 ++++ lib/view_models/providers_view_model.dart | 18 +- lib/views/dashboard/dashboard_page.dart | 7 +- .../fragments/branches_fragment.dart | 167 ++++++++++++++++++ .../dashboard/widgets/bottom_nav_bar.dart | 6 +- pubspec.yaml | 2 +- 8 files changed, 226 insertions(+), 8 deletions(-) create mode 100644 lib/repositories/provider_repo.dart create mode 100644 lib/views/dashboard/fragments/branches_fragment.dart diff --git a/lib/config/customer_dependencies.dart b/lib/config/customer_dependencies.dart index 53792ef..3debdff 100644 --- a/lib/config/customer_dependencies.dart +++ b/lib/config/customer_dependencies.dart @@ -1,8 +1,10 @@ +import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:mc_common_app/config/dependencies.dart'; class CustomerDependencies { static void addDependencies() { AppDependencies.addDependencies(); + injector.registerSingleton(() => ProviderRepoImp()); } } diff --git a/lib/main.dart b/lib/main.dart index f518977..e053104 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ 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/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'; @@ -56,6 +57,7 @@ Future main() async { create: (_) => ProvidersVM( commonServices: injector.get(), commonRepo: injector.get(), + providerRepo: injector.get(), ), ), ChangeNotifierProvider( diff --git a/lib/repositories/provider_repo.dart b/lib/repositories/provider_repo.dart new file mode 100644 index 0000000..a0d63e6 --- /dev/null +++ b/lib/repositories/provider_repo.dart @@ -0,0 +1,30 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:http/http.dart' as http; + +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/m_response.dart'; +import 'package:mc_common_app/models/model/branch2.dart'; +import 'package:mc_common_app/models/profile/branch.dart'; +import 'package:mc_common_app/models/profile/categroy.dart'; +import 'package:mc_common_app/models/profile/document.dart'; +import 'package:mc_common_app/models/profile/services.dart'; +import 'package:flutter/cupertino.dart'; + +abstract class ProviderRepo { + Future getBranchAndServices(); +} + +class ProviderRepoImp implements ProviderRepo { + @override + Future getBranchAndServices() async { + // var postParams = {"serviceProviderID": AppState().getUser.data?.userInfo?.providerId.toString() ?? ""}; + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().getJsonForObject((json) => Branch2.fromJson(json), ApiConsts.BranchesAndServices, token: t); + } +} diff --git a/lib/view_models/providers_view_model.dart b/lib/view_models/providers_view_model.dart index bc65880..96ad83e 100644 --- a/lib/view_models/providers_view_model.dart +++ b/lib/view_models/providers_view_model.dart @@ -1,15 +1,21 @@ +import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:flutter/cupertino.dart'; +import 'package:mc_common_app/models/model/branch2.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 ChangeNotifier { +class ProvidersVM extends BaseVM { final CommonRepo commonRepo; final CommonAppServices commonServices; + final ProviderRepo providerRepo; - ProvidersVM({required this.commonServices, required this.commonRepo}); + ProvidersVM({required this.commonServices, required this.commonRepo, required this.providerRepo}); List providersFilterOptions = []; + Branch2? branches; populateProvidersFilterList() { providersFilterOptions.clear(); @@ -32,4 +38,12 @@ class ProvidersVM extends ChangeNotifier { providersFilterOptions[index].isSelected = true; notifyListeners(); } + + //Create new branch + getAllNearBranches() async { + //TODO: needs to lat,long into API + branches = null; + branches = await providerRepo.getBranchAndServices(); + setState(ViewState.idle); + } } diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index 921bea8..1c9fa86 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -17,6 +17,8 @@ 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'; +import 'fragments/branches_fragment.dart'; + class DashboardPage extends StatefulWidget { const DashboardPage({Key? key}) : super(key: key); @@ -36,6 +38,7 @@ class _DashboardPageState extends State { context.read().populateAppointmentsFilterList(); context.read().populateProvidersFilterList(); context.read().populateAdsFilterList(); + context.read().getAllNearBranches(); _onRefresh(); }); } @@ -57,7 +60,7 @@ class _DashboardPageState extends State { fetchUsername() async {} List fragments = [ - const ProvidersFragment(), + const BranchesFragment(), const AppointmentsFragment(), const HomeFragment(), AdsFragment(), @@ -66,7 +69,7 @@ class _DashboardPageState extends State { String getPageTitle(int index) { if (index == 0) { - return "Providers"; + return "Branchs"; } if (index == 1) { return "Appointments"; diff --git a/lib/views/dashboard/fragments/branches_fragment.dart b/lib/views/dashboard/fragments/branches_fragment.dart new file mode 100644 index 0000000..5915432 --- /dev/null +++ b/lib/views/dashboard/fragments/branches_fragment.dart @@ -0,0 +1,167 @@ +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/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/utils/enums.dart'; + +import 'package:mc_common_app/widgets/common_widgets/categories_list.dart'; + +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geolocator/geolocator.dart'; + +class BranchesFragment extends StatelessWidget { + const BranchesFragment({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Consumer( + builder: (BuildContext context, ProvidersVM providersVM, Widget? child) { + return Column( + children: [ + 16.height, + FiltersList( + filterList: providersVM.providersFilterOptions, + onFilterTapped: (index, selectedFilterId) => providersVM.applyFilterOnProviders(index: index), + ), + 16.height, + // Expanded( + // child: Container( + // child: ListView.builder( + // shrinkWrap: true, + // itemCount: 30, + // itemBuilder: (BuildContext context, int index) { + // return ProviderDetailsCard( + // onCardTapped: () { + // if (context.read().providerCategories.isEmpty) { + // context.read().getProviderCategories(); + // } + // navigateWithName(context, AppRoutes.bookAppointmenServicesView); + // }, + // providerImageUrl: MyAssets.bnCar, + // providerLocation: " 3km", + // providerName: "Al Ahmed Maintenance", + // providerRatings: "4.9", + // ); + // }, + // ), + // ), + // ), + + Expanded( + child: RefreshIndicator( + onRefresh: () async { + context.read().getAllNearBranches(); + }, + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Consumer( + builder: (context, model, _) { + if (model.state == ViewState.busy) { + return const Center(child: CircularProgressIndicator()); + } else { + return model.branches?.data == null + ? const Center(child: Text("No Branch Found")) + : model.branches!.data!.serviceProviderBranch!.isEmpty + ? Center(child: Text(LocaleKeys.no_branch.tr())) + : ListView.separated( + itemBuilder: (context, index) { + return Row( + children: [ + Container( + width: 74, + height: 50, + decoration: const BoxDecoration( + color: MyColors.darkPrimaryColor, + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + padding: const EdgeInsets.all(6), + child: SvgPicture.asset( + MyAssets.icBranches, + color: Colors.white, + ), + ), + 12.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.place, + size: 12, + color: MyColors.darkPrimaryColor, + ), + //TODO: needs to implement get user location after login + Geolocator.distanceBetween( + // AppState().currentLocation.latitude, + // AppState().currentLocation.latitude, + 24.700590, + 46.670110, + double.parse(model.branches!.data!.serviceProviderBranch![index].latitude ?? "0"), + double.parse(model.branches!.data!.serviceProviderBranch![index].longitude ?? "0")) + .toStringAsFixed(2) + .toText( + fontSize: 12, + color: MyColors.darkPrimaryColor, + ) + ], + ), + Text( + model.branches!.data!.serviceProviderBranch![index].branchName ?? "", + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + LocaleKeys.tapToEdit.tr().toText(fontSize: 10, color: MyColors.grey70Color), + ], + ), + ), + 12.width, + const Icon( + Icons.arrow_forward_rounded, + size: 16, + ), + ], + ).toContainer().onPress(() async { + // await navigateWithName(context, AppRoutes.defineBranch, arguments: snapshot.data!.data![index]); + // setState(() {}); + // model.branchs!.data!.serviceProviderBranch![index].countryID = model.branchs!.data!.countryID; + // model.branchs!.data!.serviceProviderBranch![index].countryName = model.branchs!.data!.countryName; + // navigateWithName(context, ProviderAppRoutes.branchDetail, arguments: model.branchs!.data!.serviceProviderBranch![index]); + }); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + itemCount: model.branches!.data!.serviceProviderBranch!.length, + padding: const EdgeInsets.all(12), + ); + } + }, + ), + ), + ), + ), + ], + ); + }, + ), + ); + } +} diff --git a/lib/views/dashboard/widgets/bottom_nav_bar.dart b/lib/views/dashboard/widgets/bottom_nav_bar.dart index b8ea535..c7b9159 100644 --- a/lib/views/dashboard/widgets/bottom_nav_bar.dart +++ b/lib/views/dashboard/widgets/bottom_nav_bar.dart @@ -17,9 +17,9 @@ class CustomBottomNavbar extends StatelessWidget { return BottomNavigationBar( items: [ BottomNavigationBarItem( - icon: SvgPicture.asset(MyAssets.providersIcon).paddingAll(5), - activeIcon: SvgPicture.asset(MyAssets.providersIcon, color: MyColors.darkIconColor).paddingAll(5), - label: LocaleKeys.providers.tr(), + icon: SvgPicture.asset(MyAssets.branchesIcon).paddingAll(5), + activeIcon: SvgPicture.asset(MyAssets.branchesIcon, color: MyColors.darkIconColor).paddingAll(5), + label: LocaleKeys.branches.tr(), ), BottomNavigationBarItem( icon: SvgPicture.asset(MyAssets.appointmentsIcon).paddingAll(5), diff --git a/pubspec.yaml b/pubspec.yaml index 1c5a0d4..46981f4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: cupertino_icons: ^1.0.2 mc_common_app: - path: D:/Development/car_common_app + path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app dev_dependencies: flutter_test: From 4ccbf361fec0a9f5dca85dd9746c7bde892760e0 Mon Sep 17 00:00:00 2001 From: "mirza.shafique" Date: Thu, 15 Jun 2023 16:08:53 +0300 Subject: [PATCH 2/3] Fetch Branches & services --- lib/config/customer_routes.dart | 3 + lib/repositories/provider_repo.dart | 7 +- lib/view_models/providers_view_model.dart | 8 +- lib/views/appointments/pick_items_view.dart | 10 +- .../fragments/branches_fragment.dart | 161 ++++---------- .../fragments/providers_fragment.dart | 1 + lib/views/provider/branch_detail_page.dart | 208 ++++++++++++++++++ 7 files changed, 266 insertions(+), 132 deletions(-) create mode 100644 lib/views/provider/branch_detail_page.dart diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index 3345264..ad6774b 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -2,10 +2,12 @@ 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/pick_items_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: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/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'; @@ -19,5 +21,6 @@ class CustomerAppRoutes { AppRoutes.createAdView: (context) => CreateAdView(), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), + AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchModel: ModalRoute.of(context)!.settings.arguments as BranchModel), }; } diff --git a/lib/repositories/provider_repo.dart b/lib/repositories/provider_repo.dart index a0d63e6..4f0c64f 100644 --- a/lib/repositories/provider_repo.dart +++ b/lib/repositories/provider_repo.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:mc_common_app/models/services/near_branch_model.dart'; import 'package:http/http.dart' as http; import 'package:mc_common_app/api/api_client.dart'; @@ -17,14 +18,14 @@ import 'package:mc_common_app/models/profile/services.dart'; import 'package:flutter/cupertino.dart'; abstract class ProviderRepo { - Future getBranchAndServices(); + Future getAllNearBranchAndServices(); } class ProviderRepoImp implements ProviderRepo { @override - Future getBranchAndServices() async { + Future getAllNearBranchAndServices() async { // var postParams = {"serviceProviderID": AppState().getUser.data?.userInfo?.providerId.toString() ?? ""}; String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().getJsonForObject((json) => Branch2.fromJson(json), ApiConsts.BranchesAndServices, token: t); + return await injector.get().getJsonForObject((json) => NearBrancheModel.fromJson(json), ApiConsts.GetAllNearBranches, token: t); } } diff --git a/lib/view_models/providers_view_model.dart b/lib/view_models/providers_view_model.dart index 96ad83e..873c3f9 100644 --- a/lib/view_models/providers_view_model.dart +++ b/lib/view_models/providers_view_model.dart @@ -1,3 +1,4 @@ +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/model/branch2.dart'; @@ -15,7 +16,7 @@ class ProvidersVM extends BaseVM { ProvidersVM({required this.commonServices, required this.commonRepo, required this.providerRepo}); List providersFilterOptions = []; - Branch2? branches; + NearBrancheModel? branches; populateProvidersFilterList() { providersFilterOptions.clear(); @@ -40,10 +41,11 @@ class ProvidersVM extends BaseVM { } //Create new branch - getAllNearBranches() async { + getAllNearBranches({bool isNeedToRebuild = false}) async { //TODO: needs to lat,long into API branches = null; - branches = await providerRepo.getBranchAndServices(); + if (isNeedToRebuild) setState(ViewState.busy); + branches = await providerRepo.getAllNearBranchAndServices(); setState(ViewState.idle); } } diff --git a/lib/views/appointments/pick_items_view.dart b/lib/views/appointments/pick_items_view.dart index 0a51fa6..bd8c1e6 100644 --- a/lib/views/appointments/pick_items_view.dart +++ b/lib/views/appointments/pick_items_view.dart @@ -42,7 +42,7 @@ class _BookProviderAppViewState extends State { onCardTapped: () {}, providerImageUrl: MyAssets.bnCar, providerLocation: "3km", - providerName: "Al Ahmed Maintenance", + title: "Al Ahmed Maintenance", providerRatings: "4.9", ), 12.height, @@ -90,19 +90,19 @@ class ServicesSelectionSection extends StatelessWidget { "Select services you want".toText(fontSize: 18, isBold: true), 8.height, DropdownField( - (DropValue value) {}, + (DropValue value) {}, list: dropList, hint: "Select service type", ), 8.height, DropdownField( - (DropValue value) {}, + (DropValue value) {}, list: dropList, hint: "Select service type", ), 8.height, DropdownField( - (DropValue value) {}, + (DropValue value) {}, list: dropList, hint: "Select service type", ), @@ -110,7 +110,7 @@ class ServicesSelectionSection extends StatelessWidget { "Select date and time".toText(fontSize: 18, isBold: true), 8.height, DropdownField( - (DropValue value) {}, + (DropValue value) {}, list: dropList, hint: "Select service type", ), diff --git a/lib/views/dashboard/fragments/branches_fragment.dart b/lib/views/dashboard/fragments/branches_fragment.dart index 5915432..d0ab34c 100644 --- a/lib/views/dashboard/fragments/branches_fragment.dart +++ b/lib/views/dashboard/fragments/branches_fragment.dart @@ -2,20 +2,16 @@ 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'; 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/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/extensions/extensions_widget.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'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:geolocator/geolocator.dart'; class BranchesFragment extends StatelessWidget { const BranchesFragment({Key? key}) : super(key: key); @@ -36,124 +32,47 @@ class BranchesFragment extends StatelessWidget { onFilterTapped: (index, selectedFilterId) => providersVM.applyFilterOnProviders(index: index), ), 16.height, - // Expanded( - // child: Container( - // child: ListView.builder( - // shrinkWrap: true, - // itemCount: 30, - // itemBuilder: (BuildContext context, int index) { - // return ProviderDetailsCard( - // onCardTapped: () { - // if (context.read().providerCategories.isEmpty) { - // context.read().getProviderCategories(); - // } - // navigateWithName(context, AppRoutes.bookAppointmenServicesView); - // }, - // providerImageUrl: MyAssets.bnCar, - // providerLocation: " 3km", - // providerName: "Al Ahmed Maintenance", - // providerRatings: "4.9", - // ); - // }, - // ), - // ), - // ), - Expanded( child: RefreshIndicator( onRefresh: () async { - context.read().getAllNearBranches(); + context.read().getAllNearBranches(isNeedToRebuild: true); }, - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: Consumer( - builder: (context, model, _) { - if (model.state == ViewState.busy) { - return const Center(child: CircularProgressIndicator()); - } else { - return model.branches?.data == null - ? const Center(child: Text("No Branch Found")) - : model.branches!.data!.serviceProviderBranch!.isEmpty - ? Center(child: Text(LocaleKeys.no_branch.tr())) - : ListView.separated( - itemBuilder: (context, index) { - return Row( - children: [ - Container( - width: 74, - height: 50, - decoration: const BoxDecoration( - color: MyColors.darkPrimaryColor, - borderRadius: BorderRadius.all(Radius.circular(8)), - ), - padding: const EdgeInsets.all(6), - child: SvgPicture.asset( - MyAssets.icBranches, - color: Colors.white, - ), - ), - 12.width, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - Icons.place, - size: 12, - color: MyColors.darkPrimaryColor, - ), - //TODO: needs to implement get user location after login - Geolocator.distanceBetween( - // AppState().currentLocation.latitude, - // AppState().currentLocation.latitude, - 24.700590, - 46.670110, - double.parse(model.branches!.data!.serviceProviderBranch![index].latitude ?? "0"), - double.parse(model.branches!.data!.serviceProviderBranch![index].longitude ?? "0")) - .toStringAsFixed(2) - .toText( - fontSize: 12, - color: MyColors.darkPrimaryColor, - ) - ], - ), - Text( - model.branches!.data!.serviceProviderBranch![index].branchName ?? "", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - LocaleKeys.tapToEdit.tr().toText(fontSize: 10, color: MyColors.grey70Color), - ], - ), - ), - 12.width, - const Icon( - Icons.arrow_forward_rounded, - size: 16, - ), - ], - ).toContainer().onPress(() async { - // await navigateWithName(context, AppRoutes.defineBranch, arguments: snapshot.data!.data![index]); - // setState(() {}); - // model.branchs!.data!.serviceProviderBranch![index].countryID = model.branchs!.data!.countryID; - // model.branchs!.data!.serviceProviderBranch![index].countryName = model.branchs!.data!.countryName; - // navigateWithName(context, ProviderAppRoutes.branchDetail, arguments: model.branchs!.data!.serviceProviderBranch![index]); - }); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - itemCount: model.branches!.data!.serviceProviderBranch!.length, - padding: const EdgeInsets.all(12), - ); - } - }, + 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) { + 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; + }, + itemCount: model.branches!.data!.length, + padding: const EdgeInsets.all(12), + ); + } + }, + ), ), ), ), diff --git a/lib/views/dashboard/fragments/providers_fragment.dart b/lib/views/dashboard/fragments/providers_fragment.dart index 235874b..09e6dab 100644 --- a/lib/views/dashboard/fragments/providers_fragment.dart +++ b/lib/views/dashboard/fragments/providers_fragment.dart @@ -43,6 +43,7 @@ class ProvidersFragment extends StatelessWidget { navigateWithName(context, AppRoutes.bookAppointmenServicesView); }, providerImageUrl: MyAssets.bnCar, + title:"", providerLocation: " 3km", providerName: "Al Ahmed Maintenance", providerRatings: "4.9", diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart new file mode 100644 index 0000000..6158696 --- /dev/null +++ b/lib/views/provider/branch_detail_page.dart @@ -0,0 +1,208 @@ +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/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/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 BranchDetailPage extends StatefulWidget { + BranchModel branchModel; + + BranchDetailPage({required this.branchModel}); + + @override + State createState() => _BranchDetailPageState(); +} + +class _BranchDetailPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Branch Detail", + ), + body: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Container( + width: double.infinity, + padding: EdgeInsets.all(21), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset(MyAssets.bnCar), + 12.height, + "${widget.branchModel.branchName} | ${widget.branchModel.serviceProviderName}".toString().toText( + fontSize: 16, + isBold: true, + ), + Row( + children: [ + (LocaleKeys.location.tr() + ":").toText(color: MyColors.lightTextColor, fontSize: 12), + 4.width, + (widget.branchModel.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), + ], + ), + 2.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + "Open Map Location".toText( + fontSize: 12, + isBold: true, + color: MyColors.primaryColor, + isUnderLine: true, + ), + 4.width, + Image.asset( + MyAssets.icRightUpPng, + height: 6, + width: 6, + color: MyColors.primaryColor, + ), + ], + ) + .padding( + EdgeInsets.symmetric(vertical: 6, horizontal: 2), + ) + .onPress( + () {}, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + "Provider Profile".toText( + fontSize: 12, + isBold: true, + color: MyColors.primaryColor, + isUnderLine: true, + ), + 2.width, + Icon( + Icons.arrow_forward, + size: 12, + color: MyColors.primaryColor, + ), + ], + ) + .padding( + EdgeInsets.symmetric(vertical: 6, horizontal: 2), + ) + .onPress( + () {}, + ), + ], + ), + 20.height, + "Services Offer".toText( + fontSize: 16, + color: MyColors.lightTextColor, + isBold: true, + ), + showServicesList(), + ], + ).toWhiteContainer( + width: double.infinity, + allPading: 12, + ), + ], + ), + ), + ), + ), + ShowFillButton( + title: "Book Appointment", + maxWidth: double.infinity, + margin: EdgeInsets.all(21), + onPressed: () {}, + ).toContainer( + paddingAll: 0, + backgroundColor: Colors.white, + ), + ], + ), + ); + } + + Widget showServicesList() { + return ListView.separated( + itemBuilder: (context, index) { + return ExpansionTile( + tilePadding: EdgeInsets.zero, + title: (widget.branchModel.branchServices![index].serviceDescription ?? "").toText( + fontSize: 16, + isBold: true, + ), + children: [ + 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"), + 8.height, + (widget.branchModel.branchServices![index].itemsCount.toString() + "+ services").toText( + fontSize: 12, + isBold: true, + color: MyColors.primaryColor, + isUnderLine: true, + ), + 20.height, + ], + ).onPress(() {}), + ], + onExpansionChanged: (value) { + setState(() { + widget.branchModel.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), + ); + }, + separatorBuilder: (context, index) { + return Divider( + height: 1, + ); + }, + itemCount: widget.branchModel.branchServices!.length, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + ); + } + + Widget showItem(String item, String value, {Color valueColor = Colors.black}) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + item.toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + 4.width, + value.toText(fontSize: 12, color: valueColor, isBold: true), + ], + ); + } +} From 274e407fa97e6fe922d79a39186e41aaab92d729 Mon Sep 17 00:00:00 2001 From: "mirza.shafique" Date: Sun, 18 Jun 2023 17:02:07 +0300 Subject: [PATCH 3/3] Branches list & provider profile 1.0 --- lib/config/customer_routes.dart | 2 + lib/repositories/provider_repo.dart | 32 ++++- lib/view_models/providers_view_model.dart | 18 ++- lib/views/provider/branch_detail_page.dart | 29 ++++- lib/views/provider/provider_profile_page.dart | 80 +++++++++++++ .../provider/sheet/items_list_sheet.dart | 112 ++++++++++++++++++ 6 files changed, 260 insertions(+), 13 deletions(-) create mode 100644 lib/views/provider/provider_profile_page.dart create mode 100644 lib/views/provider/sheet/items_list_sheet.dart diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index ad6774b..f68dfef 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -3,6 +3,7 @@ import 'package:car_customer_app/views/appointments/book_appointment_services_vi import 'package:car_customer_app/views/appointments/pick_items_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:flutter/cupertino.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; @@ -22,5 +23,6 @@ class CustomerAppRoutes { AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchModel: ModalRoute.of(context)!.settings.arguments as BranchModel), + AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), }; } diff --git a/lib/repositories/provider_repo.dart b/lib/repositories/provider_repo.dart index 4f0c64f..d92a66d 100644 --- a/lib/repositories/provider_repo.dart +++ b/lib/repositories/provider_repo.dart @@ -1,6 +1,8 @@ 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; @@ -9,16 +11,15 @@ 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/m_response.dart'; -import 'package:mc_common_app/models/model/branch2.dart'; -import 'package:mc_common_app/models/profile/branch.dart'; -import 'package:mc_common_app/models/profile/categroy.dart'; -import 'package:mc_common_app/models/profile/document.dart'; -import 'package:mc_common_app/models/profile/services.dart'; + import 'package:flutter/cupertino.dart'; abstract class ProviderRepo { Future getAllNearBranchAndServices(); + + Future getServiceItems(int serviceId); + + Future getBranchAndServices(int providerId); } class ProviderRepoImp implements ProviderRepo { @@ -28,4 +29,23 @@ class ProviderRepoImp implements ProviderRepo { String t = AppState().getUser.data!.accessToken ?? ""; return await injector.get().getJsonForObject((json) => NearBrancheModel.fromJson(json), ApiConsts.GetAllNearBranches, token: t); } + + @override + Future getServiceItems(int serviceId) async { + var queryParameters = { + "ServiceProviderServiceID": serviceId.toString(), + }; + String? token = AppState().getUser.data?.accessToken; + debugPrint(token); + return await injector + .get() + .getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? ""); + } + + @override + Future getBranchAndServices(int providerId) async { + var postParams = {"serviceProviderID": providerId.toString()}; + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().getJsonForObject((json) => ProviderModel.fromJson(json), ApiConsts.BranchesAndServices, queryParameters: postParams, token: t); + } } diff --git a/lib/view_models/providers_view_model.dart b/lib/view_models/providers_view_model.dart index 873c3f9..568f713 100644 --- a/lib/view_models/providers_view_model.dart +++ b/lib/view_models/providers_view_model.dart @@ -1,7 +1,8 @@ +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/model/branch2.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'; @@ -17,6 +18,8 @@ class ProvidersVM extends BaseVM { List providersFilterOptions = []; NearBrancheModel? branches; + ItemModel? serviceItems; + ProviderModel? providerModel; populateProvidersFilterList() { providersFilterOptions.clear(); @@ -48,4 +51,17 @@ class ProvidersVM extends BaseVM { 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); + } } diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index 6158696..f9432ae 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -1,5 +1,7 @@ +import 'package:car_customer_app/views/provider/sheet/items_list_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/generated/locale_keys.g.dart'; @@ -7,6 +9,8 @@ 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/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/bottom_sheet.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'; @@ -21,6 +25,13 @@ class BranchDetailPage extends StatefulWidget { } class _BranchDetailPageState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + if (widget.branchModel.branchServices!.length > 0) widget.branchModel.branchServices?.first.isExpanded = true; + } + @override Widget build(BuildContext context) { return Scaffold( @@ -67,6 +78,7 @@ class _BranchDetailPageState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + //TODO: Needs to implement url launcher "Open Map Location".toText( fontSize: 12, isBold: true, @@ -107,11 +119,13 @@ class _BranchDetailPageState extends State { ], ) .padding( - EdgeInsets.symmetric(vertical: 6, horizontal: 2), - ) + EdgeInsets.symmetric(vertical: 6, horizontal: 2), + ) .onPress( - () {}, - ), + () { + navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchModel.serviceProviderId); + }, + ), ], ), 20.height, @@ -120,6 +134,7 @@ class _BranchDetailPageState extends State { color: MyColors.lightTextColor, isBold: true, ), + if (widget.branchModel.branchServices!.length == 0) "No Services Available".toText(fontSize: 12, isBold: true), showServicesList(), ], ).toWhiteContainer( @@ -162,7 +177,7 @@ class _BranchDetailPageState extends State { showItem("Home service range", widget.branchModel.branchServices![index].customerLocationRange.toString() + "KM"), showItem("Charges per KM", widget.branchModel.branchServices![index].customerLocationRange.toString() + "SAR"), 8.height, - (widget.branchModel.branchServices![index].itemsCount.toString() + "+ services").toText( + (widget.branchModel.branchServices![index].itemsCount.toString() + "+ items").toText( fontSize: 12, isBold: true, color: MyColors.primaryColor, @@ -170,7 +185,9 @@ class _BranchDetailPageState extends State { ), 20.height, ], - ).onPress(() {}), + ).onPress(() { + showMyBottomSheet(context, child: ItemsListSheet(widget.branchModel.branchServices![index].providerBranchServiceId ?? 0)); + }), ], onExpansionChanged: (value) { setState(() { diff --git a/lib/views/provider/provider_profile_page.dart b/lib/views/provider/provider_profile_page.dart new file mode 100644 index 0000000..84d041f --- /dev/null +++ b/lib/views/provider/provider_profile_page.dart @@ -0,0 +1,80 @@ +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/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/empty_widget.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class ProviderProfilePage extends StatefulWidget { + int providerId; + + ProviderProfilePage({required this.providerId}); + + @override + State createState() => _ProviderProfilePageState(); +} + +class _ProviderProfilePageState extends State { + @override + void initState() { + super.initState(); + context.read().getBranchAndServices(widget.providerId ?? 0); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Provider Details", + ), + body: Container( + width: double.infinity, + height: double.infinity, + padding: EdgeInsets.all(21), + child: Consumer( + builder: (context, model, _) { + return model.providerModel == null + ? const Center(child: CircularProgressIndicator()) + : model.providerModel!.data == null + ? const EmptyWidget() + : Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //TODO: company logo/banner not added form provider app yet + Image.asset(MyAssets.bnCar), + 12.height, + model.providerModel!.data!.companyName.toString().toText( + fontSize: 16, + isBold: true, + ), + Row( + children: [ + ("Mowater Member Since:").toText(color: MyColors.lightTextColor, fontSize: 12), + 4.width, + //TODO: date is missing from API side + "2023".toText(fontSize: 12, isBold: true), + ], + ), + 4.height, + //TODO: company description not added form provider app yet + // model.providerModel!.data!.companyDescription!.toText(color: MyColors.lightTextColor, fontSize: 12), + "Some description about the provider and their years of experience and their reputation".toText(color: MyColors.lightTextColor, fontSize: 12), + ], + ).toWhiteContainer( + width: double.infinity, + allPading: 12, + ), + ], + ); + }, + ), + ), + ); + } +} diff --git a/lib/views/provider/sheet/items_list_sheet.dart b/lib/views/provider/sheet/items_list_sheet.dart new file mode 100644 index 0000000..63a8fbf --- /dev/null +++ b/lib/views/provider/sheet/items_list_sheet.dart @@ -0,0 +1,112 @@ +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter/cupertino.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; + + ItemsListSheet(this.serviceId); + + @override + State createState() => _ItemsListSheetState(); +} + +class _ItemsListSheetState extends State { + @override + void initState() { + super.initState(); + context.read().getServiceItems(widget.serviceId ?? 0); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: MediaQuery.of(context).size.height / 1.2, + child: Consumer( + builder: (context, model, _) { + return model.serviceItems == null + ? const Center(child: CircularProgressIndicator()) + : model.serviceItems!.data!.isEmpty + ? const EmptyWidget() + : ListView.separated( + itemBuilder: (BuildContext context, int index) { + return SizedBox( + width: double.infinity, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + model.serviceItems!.data![index].name.toString().toText(fontSize: 16, isBold: true), + 4.height, + showItem("Available for appointment:", (model.serviceItems!.data![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Allowing Workshop service:", (model.serviceItems!.data![index].isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Allowing home service:", (model.serviceItems!.data![index].isAppointmentCustomerLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), + 12.height, + "Service Amount".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + model.serviceItems!.data![index].price!.toText(fontSize: 22, isBold: true), + 2.width, + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: "SAR".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + ), + ], + ), + ], + ), + ), + // Padding( + // padding: const EdgeInsets.all(4.0), + // child: SvgPicture.asset( + // MyAssets.icEdit, + // width: 16, + // height: 16, + // ), + // ) + ], + ), + ).toWhiteContainer( + width: double.infinity, + allPading: 12, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return 12.height; + }, + padding: const EdgeInsets.all(20), + itemCount: model.serviceItems!.data!.length, + ); + }, + ), + ); + } + + Widget showItem(String item, String value, {Color valueColor = Colors.black}) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + item.toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + 4.width, + value.toText(fontSize: 12, color: valueColor, isBold: true), + ], + ); + } +}