diff --git a/lib/config/provider_dependencies.dart b/lib/config/provider_dependencies.dart index 7b370af..3bddfa8 100644 --- a/lib/config/provider_dependencies.dart +++ b/lib/config/provider_dependencies.dart @@ -1,9 +1,9 @@ import 'package:car_provider_app/repositories/branch_repo.dart'; import 'package:car_provider_app/repositories/items_repo.dart'; import 'package:car_provider_app/repositories/schedule_repo.dart'; -import 'package:car_provider_app/repositories/subscription_repo.dart'; import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/repositories/subscription_repo.dart'; class ProviderAppDependencies { static void addDependencies() { diff --git a/lib/config/provider_routes.dart b/lib/config/provider_routes.dart index 06384b0..bad4a2a 100644 --- a/lib/config/provider_routes.dart +++ b/lib/config/provider_routes.dart @@ -29,9 +29,12 @@ import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/views/advertisement/ads_detail_view.dart'; import 'package:mc_common_app/views/advertisement/create_ad_view.dart'; +import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart'; import 'package:mc_common_app/views/chat/chat_view.dart'; +import 'package:mc_common_app/views/payments/payment_methods_view.dart'; import '../views/dashboard/dashboard_page.dart'; @@ -67,13 +70,19 @@ class ProviderAppRoutes { static const String schedulesList = "/schedulesList"; static const String addSchedule = "/addSchedule"; + // Subscriptions + static const String mySubscriptionsPage = "/mySubscriptionsPage"; + static const String subscriptionsPage = "/subscriptionsPage"; + //Bracnh Duplication static const String matchServices = "/matchServices"; static final Map routes = { //Home page AppRoutes.dashboard: (context) => const DashboardPage(), - AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel), + AppRoutes.adsDetailView: (context) => AdsDetailView( + adDetails: + ModalRoute.of(context)!.settings.arguments as AdDetailsModel), AppRoutes.createAdView: (context) => const CreateAdView(), //setting @@ -100,13 +109,15 @@ class ProviderAppRoutes { //Requests AppRoutes.requestsDetailPage: (context) => RequestDetailPage( - requestDetailPageArguments: ModalRoute.of(context)!.settings.arguments as RequestDetailPageArguments, + requestDetailPageArguments: ModalRoute.of(context)!.settings.arguments + as RequestDetailPageArguments, ), AppRoutes.sendOfferPage: (context) => const SendOfferPage(), //Subscriptions - AppRoutes.mySubscriptionsPage: (context) => const MySubscriptionsPage(), - AppRoutes.subscriptionsPage: (context) => const SubscriptionsPage(), + mySubscriptionsPage: (context) => const MySubscriptionsPage(), + subscriptionsPage: (context) => const SubscriptionsPage(), + AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), //Services dealerUser: (context) => @@ -130,10 +141,19 @@ class ProviderAppRoutes { addSchedule: (context) => AddSchedulesPage(), //Branch Duplication - matchServices: (context) => MatchedServicesPage((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as MatchServicesArguments)), + matchServices: (context) => MatchedServicesPage( + (ModalRoute.of(context)!.settings.arguments) == null + ? null + : (ModalRoute.of(context)!.settings.arguments + as MatchServicesArguments)), AppRoutes.chatView: (context) => ChatView( - chatViewArguments: ModalRoute.of(context)!.settings.arguments as ChatViewArguments, + chatViewArguments: + ModalRoute.of(context)!.settings.arguments as ChatViewArguments, ), + + //ADS: + AppRoutes.selectAdTypeView: (context) => SelectAdTypeView( + isProvider: ModalRoute.of(context)!.settings.arguments as bool), }; } diff --git a/lib/main.dart b/lib/main.dart index 5082085..cc06bdb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,13 +2,11 @@ import 'package:car_provider_app/config/provider_dependencies.dart'; import 'package:car_provider_app/repositories/branch_repo.dart'; import 'package:car_provider_app/repositories/items_repo.dart'; import 'package:car_provider_app/repositories/schedule_repo.dart'; -import 'package:car_provider_app/repositories/subscription_repo.dart'; import 'package:car_provider_app/view_models/branch_view_model.dart'; import 'package:car_provider_app/view_models/dashboard_view_model.dart'; import 'package:car_provider_app/view_models/items_view_model.dart'; import 'package:car_provider_app/view_models/schedule_view_model.dart'; import 'package:car_provider_app/view_models/service_view_model.dart'; -import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; @@ -20,17 +18,22 @@ import 'package:mc_common_app/repositories/ads_repo.dart'; import 'package:mc_common_app/repositories/appointment_repo.dart'; import 'package:mc_common_app/repositories/chat_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; +import 'package:mc_common_app/repositories/payments_repo.dart'; import 'package:mc_common_app/repositories/provider_repo.dart'; import 'package:mc_common_app/repositories/request_repo.dart'; +import 'package:mc_common_app/repositories/subscription_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; +import 'package:mc_common_app/services/payments_service.dart'; import 'package:mc_common_app/theme/app_theme.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:mc_common_app/view_models/chat_view_model.dart'; +import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; import 'package:mc_common_app/view_models/user_view_model.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -73,7 +76,8 @@ Future main() async { ), ), ChangeNotifierProvider( - create: (_) => SubscriptionsVM(subscriptionRepo: injector.get()), + create: (_) => + SubscriptionsVM(subscriptionRepo: injector.get()), ), ChangeNotifierProvider( create: (_) => ItemsVM( @@ -114,6 +118,11 @@ Future main() async { requestRepo: injector.get(), ), ), + ChangeNotifierProvider( + create: (_) => PaymentVM( + paymentService: injector.get(), + paymentRepo: injector.get()), + ), ], child: const MyApp(), ).setupLocale()); @@ -135,12 +144,19 @@ class MyApp extends StatelessWidget { injector.get().setAppType(AppType.provider); AppState().setPostParamsModel( PostParamsModel( - languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, + languageID: + EasyLocalization.of(context)?.locale.languageCode == "ar" + ? 1 + : 2, ), ); - ThemeData data = AppTheme.getTheme(isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar"); + ThemeData data = AppTheme.getTheme( + isArabic: + EasyLocalization.of(context)?.locale.languageCode == "ar"); return MaterialApp( - theme: AppTheme.getTheme(isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar"), + theme: AppTheme.getTheme( + isArabic: + EasyLocalization.of(context)?.locale.languageCode == "ar"), debugShowCheckedModeBanner: false, localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, diff --git a/lib/repositories/subscription_repo.dart b/lib/repositories/subscription_repo.dart deleted file mode 100644 index 9617155..0000000 --- a/lib/repositories/subscription_repo.dart +++ /dev/null @@ -1,27 +0,0 @@ - -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/subscriptions_models/subscription_model.dart'; -import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart'; - - -abstract class SubscriptionRepo { - Future getAllSubscriptions(String? serviceProviderID); -} - -class SubscriptionRepoImp extends SubscriptionRepo { - @override - Future getAllSubscriptions(String? serviceProviderID) async { - String t = AppState().getUser.data!.accessToken ?? ""; - Map queryParameters = {}; - if (serviceProviderID != null) { - queryParameters = { - "ID": serviceProviderID, - }; - } - - return await injector.get().getJsonForObject((json) => SubscriptionModel.fromJson(json), ApiConsts.getAllSubscriptions, token: t, queryParameters: queryParameters); - } -} diff --git a/lib/view_models/items_view_model.dart b/lib/view_models/items_view_model.dart index 036a075..d7bda4d 100644 --- a/lib/view_models/items_view_model.dart +++ b/lib/view_models/items_view_model.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:car_provider_app/repositories/items_repo.dart'; +import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/services_models/item_model.dart'; import 'package:mc_common_app/services/common_services.dart'; @@ -20,8 +21,8 @@ class ItemsVM extends BaseVM { //Items ItemModel? serviceItems; - Future selectFile() async { - File? file = await commonServices.pickFile(fileType: FileType.image); + Future selectFile(BuildContext context) async { + File? file = await commonServices.pickFile(context,fileType: FileType.image); if (file != null) { int sizeInBytes = file.lengthSync(); diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index d395326..fceaf70 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -240,6 +240,7 @@ import 'dart:io'; import 'package:car_provider_app/repositories/branch_repo.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; @@ -297,8 +298,9 @@ class ServiceVM extends BaseVM { setState(ViewState.idle); } - Future selectFile(int index) async { + Future selectFile(BuildContext context,int index) async { final File? file = await commonServices.pickFile( + context, fileType: FileType.custom, allowedExtensions: ['png', 'pdf', 'jpeg'], ); @@ -348,12 +350,15 @@ class ServiceVM extends BaseVM { Future getAllCountriesList( BranchDetailModel? branchData, String countryCode) async { + cities = null; + country = null; setState(ViewState.busy); resetValues(); country = await commonRepo.getAllCountries(); country!.data?.forEach((element) { if (branchData != null && branchData.id != null) { if (element.id == branchData.countryID) { + countryId = element.id ?? -1; countryValue = DropValue( element.id ?? 0, countryCode == "SA" @@ -382,9 +387,10 @@ class ServiceVM extends BaseVM { Future getAllCities( BranchDetailModel? branchData, String countryCode) async { setState(ViewState.busy); - citiesDropList.clear(); + citiesDropList = []; cities = null; cityId = -1; + cityValue = null; cities = await commonRepo.getAllCites(countryId.toString()); cities!.data?.forEach((element) { if (branchData != null && branchData.id != null) { @@ -511,7 +517,7 @@ class ServiceVM extends BaseVM { Future fetchProviderServices(String branchID, String categoryId) async { servicesDropList = []; - services=null; + services = null; setState(ViewState.busy); services = await branchRepo.fetchProviderServices(branchID, categoryId); diff --git a/lib/view_models/subscriptions_view_model.dart b/lib/view_models/subscriptions_view_model.dart deleted file mode 100644 index a370bf6..0000000 --- a/lib/view_models/subscriptions_view_model.dart +++ /dev/null @@ -1,74 +0,0 @@ - -import 'package:car_provider_app/repositories/subscription_repo.dart'; -import 'package:mc_common_app/models/subscriptions_models/subscription_model.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/widgets/dropdown/dropdow_field.dart'; - -class SubscriptionsVM extends BaseVM { - final SubscriptionRepo subscriptionRepo; - - SubscriptionsVM({required this.subscriptionRepo}); - - //All Subscriptions - int selectedIndex = 0; - late DropValue selectedMothlyTab; - List monthlyTabs = []; - late SubscriptionModel allSubscriptions; - List tempSubscriptions = []; - - //My Subscriptions - - //All Subscriptions - getAllAvailableSubscriptions(String? serviceProviderID) async { - selectedIndex = 0; - setState(ViewState.busy); - allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID); - if (allSubscriptions.messageStatus == 1) { - monthlyTabs.clear(); - var idSet = {}; - for (var d in allSubscriptions.data ?? []) { - if (idSet.add(d.durationDays ?? 0)) { - monthlyTabs.add(DropValue(d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), "")); - } - } - monthlyTabs.sort((a, b) => a.value.compareTo(b.value)); - selectedMothlyTab = monthlyTabs.first; - filterSubscriptions(); - setState(ViewState.idle); - } else { - setState(ViewState.error); - } - } - - String _convertDaysToMonths(int days) { - final int months = days ~/ 30; - final int remainingDays = days % 30; - - String _result = months > 0 ? '$months Month${months > 1 ? 's' : ''}${remainingDays > 0 ? ' & ' : ''}' : ''; - _result += remainingDays > 0 ? '$remainingDays Day${remainingDays > 1 ? 's' : ''}' : ''; - return _result; - } - - filterSubscriptions() { - tempSubscriptions.clear(); - for (var element in allSubscriptions.data!) { - if (selectedMothlyTab.id == element.durationDays) { - tempSubscriptions.add(element); - } - } - } - -//My Subscriptions - getMySubscriptions(String? serviceProviderID) async { - selectedIndex = 0; - setState(ViewState.busy); - allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID); - if (allSubscriptions.messageStatus == 1) { - // allSubscriptions.data!.sort((a, b) => a.value.compareTo(b.value)); - setState(ViewState.idle); - } else { - setState(ViewState.error); - } - } -} diff --git a/lib/views/appoinments/update_appointment_page.dart b/lib/views/appoinments/update_appointment_page.dart index 177d94e..20f3c1a 100644 --- a/lib/views/appoinments/update_appointment_page.dart +++ b/lib/views/appoinments/update_appointment_page.dart @@ -80,7 +80,7 @@ class UpdateAppointmentPage extends StatelessWidget { Column( children: [ showPayNowButton(context, appointmentsVM), - 21.height, + 12.height, showCancelButton(context, appointmentsVM), ], ).paddingAll(21), @@ -102,7 +102,7 @@ class UpdateAppointmentPage extends StatelessWidget { Column( children: [ showPayNowButton(context, appointmentsVM), - 21.height, + 12.height, showPayLaterButton(context, appointmentsVM), ], ).paddingAll(21), @@ -113,7 +113,9 @@ class UpdateAppointmentPage extends StatelessWidget { AppointmentStatusEnum.workStarted) && appointmentListModel.appointmentPaymentStatusEnum == AppointmentPaymentStatusEnum.payNow) - "Waiting for the payment from the customer".toText(), + "Waiting for the payment from the customer" + .toText() + .paddingAll(21), if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.arrived && @@ -134,7 +136,7 @@ class UpdateAppointmentPage extends StatelessWidget { Column( children: [ showPayLaterButton(context, appointmentsVM), - 21.height, + 12.height, showPayNowButton(context, appointmentsVM), ], ).paddingAll(21), @@ -154,7 +156,7 @@ class UpdateAppointmentPage extends StatelessWidget { AppointmentStatusEnum.workStarted && appointmentListModel.appointmentPaymentStatusEnum == AppointmentPaymentStatusEnum.payLater) - showPayNowButton(context, appointmentsVM), + showPayNowButton(context, appointmentsVM).paddingAll(21), if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.visitCompleted) @@ -234,6 +236,7 @@ class UpdateAppointmentPage extends StatelessWidget { "appointmentID": appointmentListModel.id.toString(), "appointmentServicePaymentStatusID": 2 }); + _updateAppointment(context, appointmentListModel.branchId ?? 0); Utils.hideLoading(context); }, ); @@ -249,6 +252,7 @@ class UpdateAppointmentPage extends StatelessWidget { "appointmentID": appointmentListModel.id.toString(), "appointmentStatusID": 3 }); + _updateAppointment(context, appointmentListModel.branchId ?? 0); Utils.hideLoading(context); }, ); @@ -265,6 +269,7 @@ class UpdateAppointmentPage extends StatelessWidget { "appointmentID": appointmentListModel.id.toString(), "appointmentServicePaymentStatusID": 4 }); + _updateAppointment(context, appointmentListModel.branchId ?? 0); Utils.hideLoading(context); }, ); @@ -281,6 +286,7 @@ class UpdateAppointmentPage extends StatelessWidget { "appointmentID": appointmentListModel.id.toString(), "appointmentStatusID": 8 }); + _updateAppointment(context, appointmentListModel.branchId ?? 0); Utils.hideLoading(context); }, ); diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index 1ca21f3..612704a 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -43,10 +43,8 @@ class _DashboardPageState extends State { void initState() { super.initState(); dashboardVM = Provider.of(context, listen: false); - scheduleMicrotask(() { - context.read().populateRequestsFilterList(); - _onRefresh(); - }); + context.read().populateRequestsFilterList(); + _onRefresh(); } Future _onRefresh() async { @@ -57,32 +55,40 @@ class _DashboardPageState extends State { context.read().getBranchAndServices(); AdVM adVm = Provider.of(context, listen: false); AppointmentsVM appointmentsVM = - Provider.of(context, listen: false); + Provider.of(context, listen: false); if (appointmentsVM.myAppointments.isEmpty) { await appointmentsVM.getProviderMyAppointments({ "ServiceProviderID": injector - .get() - .getUser - .data - ?.userInfo - ?.providerId - .toString() ?? + .get() + .getUser + .data + ?.userInfo + ?.providerId + .toString() ?? "0" }); } + adVm.populateAdsFilterList(); if (adVm.myAds.isEmpty) { await adVm.getMyAds(); } + if (adVm.exploreAds.isEmpty) { await adVm.getExploreAds(); } + if (adVm.vehicleTypes.isEmpty) { + await adVm.getVehicleTypes(); + } + + if (adVm.vehicleAdsDurations.isEmpty) { + await adVm.getVehicleAdsDuration(); + } if (requestsVM.myRequests.isEmpty) { await requestsVM.getRequests(appType: AppType.provider); } - await chatVM.buildHubConnection(context); - + // await chatVM.buildHubConnection(context); } @override @@ -92,11 +98,17 @@ class _DashboardPageState extends State { onBackButtonTapped: () { dashboardVM.updateIndex(2); }, + onRefresh: () async { + context.read().getBranchAndServices(); + }, ), BranchAppointmentFragment( onBackButtonTapped: () { dashboardVM.updateIndex(2); }, + onRefresh: () async { + context.read().getBranchAndServices(); + }, ), HomeFragment( onTap: () { @@ -114,7 +126,11 @@ class _DashboardPageState extends State { dashboardVM.updateIndex(2); }, ), - const MyRequestsFragment(), + MyRequestsFragment( + onBackButtonTapped: () { + dashboardVM.updateIndex(2); + }, + ), ]; return Scaffold( diff --git a/lib/views/dashboard/fragments/branch_appointment_fragment.dart b/lib/views/dashboard/fragments/branch_appointment_fragment.dart index e2d9cc6..52cd3c3 100644 --- a/lib/views/dashboard/fragments/branch_appointment_fragment.dart +++ b/lib/views/dashboard/fragments/branch_appointment_fragment.dart @@ -24,10 +24,14 @@ import 'package:flutter_svg/flutter_svg.dart'; class BranchAppointmentFragment extends StatelessWidget { bool isNeedAppBar; VoidCallback onBackButtonTapped; + RefreshCallback onRefresh; - BranchAppointmentFragment( - {Key? key, this.isNeedAppBar = true, required this.onBackButtonTapped}) - : super(key: key); + BranchAppointmentFragment({ + Key? key, + this.isNeedAppBar = true, + required this.onBackButtonTapped, + required this.onRefresh, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -71,93 +75,96 @@ class BranchAppointmentFragment extends StatelessWidget { model.selectedBranchStatus == element.statusId) .toList(); } - return branches.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)), + return RefreshIndicator( + onRefresh: onRefresh, + child: branches.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, + ), ), - 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, + 12.width, + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.place, + size: 12, + color: MyColors.darkPrimaryColor, + ), + Geolocator.distanceBetween( + AppState() + .currentLocation + .latitude, + AppState() + .currentLocation + .latitude, + double.parse(branches[index] + .latitude ?? + "0"), + double.parse(branches[index] + .longitude ?? + "0")) + .toStringAsFixed(2) + .toText( + fontSize: 12, + color: + MyColors.darkPrimaryColor, + ) + ], + ), + Text( + branches[index].branchName ?? "", + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, ), - Geolocator.distanceBetween( - AppState() - .currentLocation - .latitude, - AppState() - .currentLocation - .latitude, - double.parse(branches[index] - .latitude ?? - "0"), - double.parse(branches[index] - .longitude ?? - "0")) - .toStringAsFixed(2) - .toText( - fontSize: 12, - color: - MyColors.darkPrimaryColor, - ) - ], - ), - Text( - branches[index].branchName ?? "", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, ), - ), - "Tap to view".toText( - fontSize: 10, - color: MyColors.grey70Color), - ], + "Tap to view".toText( + fontSize: 10, + color: MyColors.grey70Color), + ], + ), ), - ), - 12.width, - ], - ).toContainer().onPress(() async { - branches[index].countryID = - model.branches!.data!.countryID; - branches[index].countryName = - model.branches!.data!.countryName; - navigateWithName( - context, ProviderAppRoutes.appointment, - arguments: branches[index]); - }); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - itemCount: branches.length, - padding: const EdgeInsets.all(12), - ); + 12.width, + ], + ).toContainer().onPress(() async { + branches[index].countryID = + model.branches!.data!.countryID; + branches[index].countryName = + model.branches!.data!.countryName; + navigateWithName( + context, ProviderAppRoutes.appointment, + arguments: branches[index]); + }); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + itemCount: branches.length, + padding: const EdgeInsets.all(12), + ), + ); } }, ), diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index 7d24f08..7feb6e7 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -64,97 +64,95 @@ class HomeFragment extends StatelessWidget { height: double.infinity, child: RefreshIndicator( onRefresh: onRefresh, - child: SingleChildScrollView( - child: Column( - children: [ - ViewAllWidget( - title: 'Upcoming Appointment', - subTitle: 'View All', - onSubtitleTapped: () {}, - ).horPaddingMain(), - // const AppointmentSliderWidget().horPaddingMain(), - CustomerAppointmentSliderWidget( - myUpComingAppointments: - context.read().myUpComingAppointments, - isNeedToShowEmptyMessage: true, - onAppointmentClick: (){ - // navigateWithName( - // context, ProviderAppRoutes.appointment, - // arguments: branches[index]); - }, - ), - 21.height, - ViewAllWidget( - title: 'My Branches', - subTitle: 'View All', - onSubtitleTapped: () {}, - ).horPaddingMain(), - const ServiceProviderWidget().horPaddingMain(), - Consumer( - builder: (BuildContext context, AdVM adVM, Widget? child) { - if (adVM.state == ViewState.busy) { - return const Center(child: CircularProgressIndicator()); - } else { - return Column( - children: [ - if (adVM.myActiveAdsForHome.isNotEmpty) ...[ - Column( - children: [ - 15.height, - ViewAllWidget( - title: "My Active Ads", - subTitle: "View All", - onSubtitleTapped: () { - // context.read().onNavbarTapped(3); - // context.read().updateIsExploreAds(false); - }, - ).horPaddingMain(), - BuildAdsList( - shouldShowAdStatus: true, - isAdsFragment: false, - adsList: adVM.myActiveAdsForHome, - scrollPhysics: - const NeverScrollableScrollPhysics(), - ), - ], - ) - ], - if (adVM.exploreAds.isNotEmpty) ...[ - Column( - children: [ - 15.height, - ViewAllWidget( - title: "My Recommended Ads", - subTitle: "View All", - onSubtitleTapped: () { - // context.read().onNavbarTapped(3); - // context.read().updateIsExploreAds(true); - // context.read().applyFilterOnExploreAds(index: 0); - }, - ).horPaddingMain(), - BuildAdsList( - shouldShowAdStatus: false, - adsList: adVM.exploreAds.length >= 3 - ? adVM.exploreAds.take(3).toList() - : adVM.exploreAds, - isAdsFragment: false, - scrollPhysics: - const NeverScrollableScrollPhysics(), - ), - ], - ) - ] + child: ListView( + children: [ + ViewAllWidget( + title: 'Upcoming Appointment', + subTitle: 'View All', + onSubtitleTapped: () {}, + ).horPaddingMain(), + // const AppointmentSliderWidget().horPaddingMain(), + CustomerAppointmentSliderWidget( + myUpComingAppointments: + context.read().myUpComingAppointments, + isNeedToShowEmptyMessage: true, + onAppointmentClick: () { + // navigateWithName( + // context, ProviderAppRoutes.appointment, + // arguments: branches[index]); + }, + ), + 21.height, + ViewAllWidget( + title: 'My Branches', + subTitle: 'View All', + onSubtitleTapped: () {}, + ).horPaddingMain(), + const ServiceProviderWidget().horPaddingMain(), + Consumer( + builder: (BuildContext context, AdVM adVM, Widget? child) { + if (adVM.state == ViewState.busy) { + return const Center(child: CircularProgressIndicator()); + } else { + return Column( + children: [ + if (adVM.myActiveAdsForHome.isNotEmpty) ...[ + Column( + children: [ + 15.height, + ViewAllWidget( + title: "My Active Ads", + subTitle: "View All", + onSubtitleTapped: () { + // context.read().onNavbarTapped(3); + // context.read().updateIsExploreAds(false); + }, + ).horPaddingMain(), + BuildAdsList( + shouldShowAdStatus: true, + isAdsFragment: false, + adsList: adVM.myActiveAdsForHome, + scrollPhysics: + const NeverScrollableScrollPhysics(), + ), + ], + ) ], - ); - } - }, - ), - 21.height, - // const AdWidget( - // count: 4, - // ), - ], - ), + if (adVM.exploreAds.isNotEmpty) ...[ + Column( + children: [ + 15.height, + ViewAllWidget( + title: "My Recommended Ads", + subTitle: "View All", + onSubtitleTapped: () { + // context.read().onNavbarTapped(3); + // context.read().updateIsExploreAds(true); + // context.read().applyFilterOnExploreAds(index: 0); + }, + ).horPaddingMain(), + BuildAdsList( + shouldShowAdStatus: false, + adsList: adVM.exploreAds.length >= 3 + ? adVM.exploreAds.take(3).toList() + : adVM.exploreAds, + isAdsFragment: false, + scrollPhysics: + const NeverScrollableScrollPhysics(), + ), + ], + ) + ] + ], + ); + } + }, + ), + 21.height, + // const AdWidget( + // count: 4, + // ), + ], ), ), ), diff --git a/lib/views/dashboard/fragments/my_requests_fragment.dart b/lib/views/dashboard/fragments/my_requests_fragment.dart index 04e9cf3..e6e2f8f 100644 --- a/lib/views/dashboard/fragments/my_requests_fragment.dart +++ b/lib/views/dashboard/fragments/my_requests_fragment.dart @@ -15,49 +15,65 @@ import 'package:easy_localization/easy_localization.dart'; class MyRequestsFragment extends StatelessWidget { final bool isNeedAppBar; + VoidCallback onBackButtonTapped; - const MyRequestsFragment({super.key, this.isNeedAppBar = true}); + MyRequestsFragment( + {super.key, this.isNeedAppBar = true, required this.onBackButtonTapped}); @override Widget build(BuildContext context) { return Scaffold( - appBar: !isNeedAppBar ? null : CustomAppBar(title: LocaleKeys.myServiceBranches.tr()), + appBar: !isNeedAppBar + ? null + : CustomAppBar( + title: LocaleKeys.myServiceBranches.tr(), + onBackButtonTapped: onBackButtonTapped, + ), body: Container( color: MyColors.backgroundColor, width: double.infinity, height: double.infinity, - child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) { + child: Consumer(builder: + (BuildContext context, RequestsVM requestsVM, Widget? child) { return Column( children: [ 16.height, FiltersList( filterList: requestsVM.requestsTypeFilterOptions, onFilterTapped: (index, selectedFilterId) { - requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: selectedFilterId.toRequestTypeStatusEnum()); + requestsVM.applyFilterOnRequestsVM( + requestsTypeEnum: + selectedFilterId.toRequestTypeStatusEnum()); }, ), 8.height, Expanded( child: RefreshIndicator( - onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true, appType: AppType.provider), + onRefresh: () async => await requestsVM.getRequests( + isNeedToRebuild: true, appType: AppType.provider), child: requestsVM.state == ViewState.busy ? const Center(child: CircularProgressIndicator()) : requestsVM.myFilteredRequests.isEmpty ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - "No Requests to show.".toText(fontSize: 16, color: MyColors.lightTextColor), + "No Requests to show.".toText( + fontSize: 16, color: MyColors.lightTextColor), ], ) : ListView.separated( itemBuilder: (context, index) { - return RequestItem(request: requestsVM.myFilteredRequests[index], appType: AppType.provider, requestIndex: index); + return RequestItem( + request: requestsVM.myFilteredRequests[index], + appType: AppType.provider, + requestIndex: index); }, separatorBuilder: (context, index) { return 16.height; }, itemCount: requestsVM.myFilteredRequests.length, - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), + padding: const EdgeInsets.only( + left: 16, right: 16, bottom: 16, top: 8), ), )) ], diff --git a/lib/views/dashboard/widget/drawer_widget.dart b/lib/views/dashboard/widget/drawer_widget.dart index 86d9593..e366ac4 100644 --- a/lib/views/dashboard/widget/drawer_widget.dart +++ b/lib/views/dashboard/widget/drawer_widget.dart @@ -35,8 +35,14 @@ class _CustomDrawerState extends State { builder: (context) => AlertDialog( content: const Text("Choose image source"), actions: [ - TextButton(child: const Text("Camera"), onPressed: () => widget.dashboardVM.pickImageFromPhone(context, 0)), - TextButton(child: const Text("Gallery"), onPressed: () => widget.dashboardVM.pickImageFromPhone(context, 1)), + TextButton( + child: const Text("Camera"), + onPressed: () => + widget.dashboardVM.pickImageFromPhone(context, 0)), + TextButton( + child: const Text("Gallery"), + onPressed: () => + widget.dashboardVM.pickImageFromPhone(context, 1)), ], ), ); @@ -54,7 +60,13 @@ class _CustomDrawerState extends State { height: 200, color: MyColors.darkPrimaryColor.withOpacity(0.01), child: Image.network( - ApiConsts.baseUrlServices + AppState().getUser.data!.userInfo!.userImageUrl.toString(), + ApiConsts.baseUrlServices + + AppState() + .getUser + .data! + .userInfo! + .userImageUrl + .toString(), ), ), Positioned( @@ -94,11 +106,16 @@ class _CustomDrawerState extends State { color: Colors.red, ).onPress(() async { Utils.showLoading(context); - ImageResponse response = await widget.dashboardVM.updateUserImage(""); + ImageResponse response = + await widget.dashboardVM.updateUserImage(""); if (response.messageStatus == 1) { Utils.showToast("Image is Deleted"); setState(() { - AppState().getUser.data!.userInfo!.userImageUrl = response.data; + AppState() + .getUser + .data! + .userInfo! + .userImageUrl = response.data; }); } Utils.hideLoading(context); @@ -127,7 +144,12 @@ class _CustomDrawerState extends State { fontSize: 20, letterSpacing: -1.44, ), - AppState().getUser.data!.userInfo!.roleName!.toText(fontSize: 10), + AppState() + .getUser + .data! + .userInfo! + .roleName! + .toText(fontSize: 10), ], ), ), @@ -144,12 +166,21 @@ class _CustomDrawerState extends State { ), ), ListTile( - leading: SvgPicture.asset(MyAssets.nextIcon, color: MyColors.darkPrimaryColor), + leading: SvgPicture.asset(MyAssets.nextIcon, + color: MyColors.darkPrimaryColor), title: LocaleKeys.defineLicences.tr().toText(fontSize: 12), onTap: () { navigateWithName(context, ProviderAppRoutes.defineLicense); }, ), + ListTile( + leading: SvgPicture.asset(MyAssets.nextIcon, + color: MyColors.darkPrimaryColor), + title: "Subscriptions".toText(fontSize: 12), + onTap: () { + navigateWithName(context, ProviderAppRoutes.mySubscriptionsPage); + }, + ), ListTile( leading: Image.asset( MyAssets.icWorldPng, @@ -159,7 +190,8 @@ class _CustomDrawerState extends State { ), title: LocaleKeys.english.tr().toText(fontSize: 12), onTap: () { - if (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA") { + if (EasyLocalization.of(context)?.currentLocale?.countryCode == + "SA") { context.setLocale(const Locale("en", "US")); } else { context.setLocale(const Locale('ar', 'SA')); diff --git a/lib/views/location/map_selection_widget.dart b/lib/views/location/map_selection_widget.dart index 61953d1..dc28656 100644 --- a/lib/views/location/map_selection_widget.dart +++ b/lib/views/location/map_selection_widget.dart @@ -12,13 +12,15 @@ class AppMap extends StatefulWidget { late AppMapState _state; final Function onMapCreated; - AppMap(this.initialCamera, {required this.onCameraMove, required this.onMapCreated}); + AppMap(this.initialCamera, + {required this.onCameraMove, required this.onMapCreated}); @override State createState() => _state = AppMapState(); moveTo({required CameraPosition cameraPostion}) { - _state.googleMapController.animateCamera(CameraUpdate.newCameraPosition(cameraPostion)); + _state.googleMapController + .animateCamera(CameraUpdate.newCameraPosition(cameraPostion)); } } @@ -35,6 +37,12 @@ class AppMapState extends State { @override void initState() {} + @override + void dispose() { + super.dispose(); + googleMapController.dispose(); + } + @override Widget build(BuildContext context) { if (isHuawei == null) return CircularProgressIndicator(); @@ -47,7 +55,9 @@ class AppMapState extends State { zoomControlsEnabled: true, myLocationButtonEnabled: true, myLocationEnabled: true, - initialCameraPosition: CameraPosition.fromMap(widget.initialCamera) ?? const CameraPosition(target: LatLng(-26.1711459, 27.9002758), zoom: 2.0), + initialCameraPosition: CameraPosition.fromMap(widget.initialCamera) ?? + const CameraPosition( + target: LatLng(-26.1711459, 27.9002758), zoom: 2.0), onCameraMove: widget.onCameraMove, onMapCreated: (GoogleMapController controller) { googleMapController = controller; diff --git a/lib/views/location/pick_location_page.dart b/lib/views/location/pick_location_page.dart index e7ef5aa..742bdf0 100644 --- a/lib/views/location/pick_location_page.dart +++ b/lib/views/location/pick_location_page.dart @@ -54,6 +54,11 @@ class _PickLocationPageState extends State { super.initState(); } + @override + void dispose() { + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -117,10 +122,7 @@ class _PickLocationPageState extends State { Future _updatePosition(CameraPosition _position) async { latitude = _position.target.latitude; longitude = _position.target.longitude; - // List placemarks = await placemarkFromCoordinates(latitude, longitude); - // _counter.value = '${placemarks.first.street}, ${placemarks.first.subLocality}, ${placemarks.first.locality}, ${placemarks.first.postalCode}, ${placemarks.first.country}'; - print("Address121: " + _counter.value); - // _counter.value = (placemarks.first.name) ?? "" + " " + (placemarks.first.street ?? "") + " " + (placemarks.first.country ?? ""); + updateAddress(latitude, longitude); } void _getUserLocation() async { @@ -130,21 +132,32 @@ class _PickLocationPageState extends State { latitude = position.latitude; longitude = position.longitude; setMap(); + updateAddress(latitude, longitude); } else { requestPermissions().then( (value) async { if (value[Permission.location]!.isGranted) { - var position = await GeolocatorPlatform.instance.getCurrentPosition(); + var position = + await GeolocatorPlatform.instance.getCurrentPosition(); currentPostion = LatLng(position.latitude, position.longitude); latitude = position.latitude; longitude = position.longitude; setMap(); + updateAddress(latitude, longitude); } }, ); } } + updateAddress(double latitude, double longitude) async { + // List placemarks = + // await placemarkFromCoordinates(latitude, longitude); + // _counter.value = + // '${placemarks.first.street}, ${placemarks.first.subLocality}, ${placemarks.first.locality}, ${placemarks.first.postalCode}, ${placemarks.first.country}'; + // print("Address121: " + placemarks[0].toString()); + } + setMap() { setState(() { _kGooglePlex = CameraPosition( diff --git a/lib/views/settings/branch/branch_detail_page.dart b/lib/views/settings/branch/branch_detail_page.dart index 35e92c6..27bb5bd 100644 --- a/lib/views/settings/branch/branch_detail_page.dart +++ b/lib/views/settings/branch/branch_detail_page.dart @@ -76,11 +76,14 @@ class BranchDetailPage extends StatelessWidget { Row( children: [ Expanded( - child: titleWidget(MyAssets.icBranches, LocaleKeys.branchInfo.tr()), + child: titleWidget(MyAssets.icBranches, + LocaleKeys.branchInfo.tr()), ), IconButton( onPressed: () { - navigateWithName(context, ProviderAppRoutes.defineBranch, arguments: branchData); + navigateWithName( + context, ProviderAppRoutes.defineBranch, + arguments: branchData); }, icon: SvgPicture.asset(MyAssets.icEdit), ) @@ -88,11 +91,17 @@ class BranchDetailPage extends StatelessWidget { ), Column( children: [ - showData("${LocaleKeys.country.tr()}:", "branchData.countryName".toString()), - showData("${LocaleKeys.city.tr()}:", "branchData.cityName".toString()), - showData("${LocaleKeys.branchName.tr()}:", branchData.branchName.toString()), - showData("${LocaleKeys.branchDescription.tr()}:", branchData.branchDescription.toString()), - showData("${LocaleKeys.address.tr()}:", branchData.address.toString()), + showData("${LocaleKeys.country.tr()}:", + branchData.countryName.toString()), + showData("${LocaleKeys.city.tr()}:", + branchData.cityName.toString()), + showData("${LocaleKeys.branchName.tr()}:", + branchData.branchName.toString()), + showData( + "${LocaleKeys.branchDescription.tr()}:", + branchData.branchDescription.toString()), + showData("${LocaleKeys.address.tr()}:", + branchData.address.toString()), ], ), ], @@ -101,7 +110,8 @@ class BranchDetailPage extends StatelessWidget { Container( width: double.infinity, color: MyColors.darkIconColor, - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 8), child: Row( children: [ const Icon( @@ -125,7 +135,9 @@ class BranchDetailPage extends StatelessWidget { ], ), ).onPress(() { - navigateWithName(context, ProviderAppRoutes.schedulesList, arguments: branchData.id.toString()); + navigateWithName( + context, ProviderAppRoutes.schedulesList, + arguments: branchData.id.toString()); }), Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -152,7 +164,8 @@ class BranchDetailPage extends StatelessWidget { backgroundColor: MyColors.darkWhiteColor, width: double.infinity, paddingAll: 20, - margin: const EdgeInsets.only(left: 20, right: 20, top: 20), + margin: + const EdgeInsets.only(left: 20, right: 20, top: 20), ) .onPress(() { navigateWithName( @@ -165,17 +178,22 @@ class BranchDetailPage extends StatelessWidget { ); }), categories.isEmpty - ? LocaleKeys.no_branch.tr().toText(fontSize: 12) + ? "No Service Added Yet".toText(fontSize: 12) : ListView.separated( itemBuilder: (context, pIndex) { return InkWell( onTap: () { - categories[pIndex].branchId = branchData.id.toString(); - categories[pIndex].branchName = branchData.branchName.toString(); - navigateWithName(context, ProviderAppRoutes.servicesList, arguments: categories[pIndex]); + categories[pIndex].branchId = + branchData.id.toString(); + categories[pIndex].branchName = + branchData.branchName.toString(); + navigateWithName( + context, ProviderAppRoutes.servicesList, + arguments: categories[pIndex]); }, child: Row( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Padding( @@ -189,12 +207,19 @@ class BranchDetailPage extends StatelessWidget { 8.width, Expanded( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, children: [ Row( children: [ - categories[pIndex].categoryName.toString().toText(fontSize: 16, isBold: true), + categories[pIndex] + .categoryName + .toString() + .toText( + fontSize: 16, + isBold: true), // Padding( // padding: const EdgeInsets.all(4.0), // child: SvgPicture.asset( @@ -204,26 +229,46 @@ class BranchDetailPage extends StatelessWidget { // ), // ), ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, ), Row( children: [ Expanded( child: ListView.builder( - itemBuilder: (context, index) { + itemBuilder: + (context, index) { return Container( - child: (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" - ? categories[pIndex].services![index].serviceDescriptionN.toString() - : categories[pIndex].services![index].serviceDescription.toString()) + child: (EasyLocalization.of( + context) + ?.currentLocale + ?.countryCode == + "SA" + ? categories[ + pIndex] + .services![ + index] + .serviceDescriptionN + .toString() + : categories[ + pIndex] + .services![ + index] + .serviceDescription + .toString()) .toText( fontSize: 12, - color: MyColors.lightTextColor, + color: MyColors + .lightTextColor, isBold: true, ), ); }, - itemCount: categories[pIndex].services?.length, - physics: const NeverScrollableScrollPhysics(), + itemCount: categories[pIndex] + .services + ?.length, + physics: + const NeverScrollableScrollPhysics(), shrinkWrap: true, padding: EdgeInsets.zero, ), @@ -236,15 +281,18 @@ class BranchDetailPage extends StatelessWidget { ), ), ], - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.end, + crossAxisAlignment: + CrossAxisAlignment.end, ) ], )), ], ).toContainer( width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), isShadowEnabled: true, ), ); @@ -253,7 +301,8 @@ class BranchDetailPage extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.all(20), - separatorBuilder: (BuildContext context, int index) { + separatorBuilder: + (BuildContext context, int index) { return 12.height; }, ), @@ -278,7 +327,8 @@ class BranchDetailPage extends StatelessWidget { txtColor: MyColors.darkPrimaryColor, isFilled: false, onPressed: () { - navigateWithName(context, ProviderAppRoutes.dealerUser, arguments: branchData.id.toString()); + navigateWithName(context, ProviderAppRoutes.dealerUser, + arguments: branchData.id.toString()); }, ), ), diff --git a/lib/views/settings/branch/branch_list_page.dart b/lib/views/settings/branch/branch_list_page.dart index ac16203..dab6a8c 100644 --- a/lib/views/settings/branch/branch_list_page.dart +++ b/lib/views/settings/branch/branch_list_page.dart @@ -27,8 +27,14 @@ import 'package:provider/provider.dart'; class BranchListPage extends StatelessWidget { bool isNeedAppBar; VoidCallback onBackButtonTapped; + RefreshCallback onRefresh; - BranchListPage({Key? key, this.isNeedAppBar = true, required this.onBackButtonTapped}) : super(key: key); + BranchListPage( + {Key? key, + this.isNeedAppBar = true, + required this.onRefresh, + required this.onBackButtonTapped}) + : super(key: key); @override Widget build(BuildContext context) { @@ -56,7 +62,9 @@ class BranchListPage extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 21, right: 21, top: 21), child: RoleTypeTab( - context.watch().selectedBranchStatus == 3 ? 0 : context.watch().selectedBranchStatus, + context.watch().selectedBranchStatus == 3 + ? 0 + : context.watch().selectedBranchStatus, [ DropValue(3, "Active", ""), DropValue(1, "Requested", ""), @@ -74,95 +82,130 @@ class BranchListPage extends StatelessWidget { } else { List branches = []; if (model.branches!.data != null) { - branches = model.branches!.data!.serviceProviderBranch!.where((element) => model.selectedBranchStatus == element.statusId).toList(); + branches = model.branches!.data!.serviceProviderBranch! + .where((element) => + model.selectedBranchStatus == element.statusId) + .toList(); } - return branches.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)), + return RefreshIndicator( + onRefresh: onRefresh, + child: branches.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, + ), ), - 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, + 12.width, + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.place, + size: 12, + color: MyColors.darkPrimaryColor, + ), + Geolocator.distanceBetween( + AppState() + .currentLocation + .latitude, + AppState() + .currentLocation + .latitude, + double.parse(branches[index] + .latitude ?? + "0"), + double.parse(branches[index] + .longitude ?? + "0")) + .toStringAsFixed(2) + .toText( + fontSize: 12, + color: + MyColors.darkPrimaryColor, + ) + ], + ), + Text( + branches[index].branchName ?? "", + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, ), - Geolocator.distanceBetween(AppState().currentLocation.latitude, AppState().currentLocation.latitude, double.parse(branches[index].latitude ?? "0"), - double.parse(branches[index].longitude ?? "0")) - .toStringAsFixed(2) - .toText( - fontSize: 12, - color: MyColors.darkPrimaryColor, - ) - ], - ), - Text( - branches[index].branchName ?? "", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, ), - ), - LocaleKeys.tapToEdit.tr().toText(fontSize: 10, color: MyColors.grey70Color), - ], + LocaleKeys.tapToEdit.tr().toText( + fontSize: 10, + color: MyColors.grey70Color), + ], + ), + ), + 12.width, + IconButton( + onPressed: () async { + Utils.showLoading(context); + MResponse res = await model.updateBranch( + branches[index].id ?? 0, + branches[index].branchName ?? "", + branches[index].branchDescription ?? + "", + branches[index].cityId.toString(), + branches[index].address ?? "", + branches[index].latitude.toString(), + branches[index].longitude.toString(), + isNeedToDelete: false); + Utils.hideLoading(context); + if (res.messageStatus == 1) { + Utils.showToast( + LocaleKeys.branch_deleted.tr()); + model.setState(ViewState.idle); + } else { + Utils.showToast(res.message ?? ""); + } + }, + icon: const Icon(Icons.delete), + color: Colors.red, + ), + const Icon( + Icons.arrow_forward_rounded, + size: 16, ), - ), - 12.width, - IconButton( - onPressed: () async { - Utils.showLoading(context); - MResponse res = await model.updateBranch(branches[index].id ?? 0, branches[index].branchName ?? "", branches[index].branchDescription ?? "", - branches[index].cityId.toString(), branches[index].address ?? "", branches[index].latitude.toString(), branches[index].longitude.toString(), - isNeedToDelete: false); - Utils.hideLoading(context); - if (res.messageStatus == 1) { - Utils.showToast(LocaleKeys.branch_deleted.tr()); - model.setState(ViewState.idle); - } else { - Utils.showToast(res.message ?? ""); - } - }, - icon: const Icon(Icons.delete), - color: Colors.red, - ), - const Icon( - Icons.arrow_forward_rounded, - size: 16, - ), - ], - ).toContainer().onPress(() async { - branches[index].countryID = model.branches!.data!.countryID; - branches[index].countryName = model.branches!.data!.countryName; - navigateWithName(context, ProviderAppRoutes.branchDetail, arguments: branches[index]); - }); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - itemCount: branches.length, - padding: const EdgeInsets.all(12), - ); + ], + ).toContainer().onPress(() async { + branches[index].countryID = + model.branches!.data!.countryID; + branches[index].countryName = + model.branches!.data!.countryName; + navigateWithName( + context, ProviderAppRoutes.branchDetail, + arguments: branches[index]); + }); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + itemCount: branches.length, + padding: const EdgeInsets.all(12), + ), + ); } }, ), diff --git a/lib/views/settings/branch/dealer/dealer_user_page.dart b/lib/views/settings/branch/dealer/dealer_user_page.dart index cef765d..8740a01 100644 --- a/lib/views/settings/branch/dealer/dealer_user_page.dart +++ b/lib/views/settings/branch/dealer/dealer_user_page.dart @@ -111,8 +111,8 @@ class _DealerUserPageState extends State { ("${model.branchUserList[index].firstName} ${model.branchUserList[index].lastName}").toText(fontSize: 16, isBold: true), 8.height, itemWidget("Role", "Dealer User"), - itemWidget("Email", model.branchUserList[index].email), - itemWidget("Phone", model.branchUserList[index].mobileNo) + itemWidget("Email", model.branchUserList[index].email??""), + itemWidget("Phone", model.branchUserList[index].mobileNo??"") ], ), ), diff --git a/lib/views/settings/branch/dealer/widget/assign_dealer_user_sheet.dart b/lib/views/settings/branch/dealer/widget/assign_dealer_user_sheet.dart index b477352..552b393 100644 --- a/lib/views/settings/branch/dealer/widget/assign_dealer_user_sheet.dart +++ b/lib/views/settings/branch/dealer/widget/assign_dealer_user_sheet.dart @@ -90,7 +90,7 @@ class _AssignDealerUserSheetState extends State { Utils.showLoading(context); List userIds = []; for (var element in provider.allProviderDealersList) { - if (element.isBranchUser) { + if (element.isBranchUser??false) { userIds.add(element.id); } } @@ -156,8 +156,8 @@ class _AssignDealerUserSheetState extends State { ("${model.allProviderDealersList[index].firstName} ${model.allProviderDealersList[index].lastName}").toText(fontSize: 16, isBold: true), 8.height, itemWidget("Role", "Dealer User"), - itemWidget("Email", model.allProviderDealersList[index].email), - itemWidget("Phone", model.allProviderDealersList[index].mobileNo) + itemWidget("Email", model.allProviderDealersList[index].email??""), + itemWidget("Phone", model.allProviderDealersList[index].mobileNo??"") ], ), ), @@ -181,7 +181,7 @@ class _AssignDealerUserSheetState extends State { bool validation() { bool isValid = false; for (var element in provider.allProviderDealersList) { - if (element.isBranchUser) { + if (element.isBranchUser??false) { isValid = true; } } diff --git a/lib/views/settings/branch/define_branch_page.dart b/lib/views/settings/branch/define_branch_page.dart index b3080cd..2ab44dc 100644 --- a/lib/views/settings/branch/define_branch_page.dart +++ b/lib/views/settings/branch/define_branch_page.dart @@ -28,7 +28,8 @@ class DefineBranchPage extends StatelessWidget { @override Widget build(BuildContext context) { ServiceVM branchVM = context.read(); - branchVM.getAllCountriesList(branchData, EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); + branchVM.getAllCountriesList(branchData, + EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); return Scaffold( appBar: CustomAppBar( title: LocaleKeys.defineBranches.tr(), @@ -50,10 +51,18 @@ class DefineBranchPage extends StatelessWidget { model.country != null ? DropdownField( (DropValue value) { + model.countryValue = + DropValue(value.id, value.value, ""); model.countryCode = value.subValue; model.countryId = value.id; - model.getAllCities(branchData, EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); + model.getAllCities( + branchData, + EasyLocalization.of(context) + ?.currentLocale + ?.countryCode ?? + "SA"); }, + isSelectAble: branchData == null ? true : false, list: model.countryDropList, dropdownValue: model.countryValue, hint: "${LocaleKeys.chooseCountry.tr()}*", @@ -66,7 +75,8 @@ class DefineBranchPage extends StatelessWidget { ? Text(LocaleKeys.no_city_available.tr()) : DropdownField( (DropValue value) { - // countryCode = value.subValue; + model.cityValue = DropValue( + value.id, value.value, ""); model.setOnlyState(ViewState.busy); model.cityId = value.id; model.setState(ViewState.idle); @@ -111,7 +121,9 @@ class DefineBranchPage extends StatelessWidget { navigateTo( context, PickLocationPage( - onPickAddress: (double latitude, double longitude, String address) { + onPickAddress: (double latitude, + double longitude, String address) { + print("tesssgngl " + address); model.latitude = latitude; model.longitude = longitude; model.address = address; @@ -125,12 +137,16 @@ class DefineBranchPage extends StatelessWidget { height: 45, decoration: BoxDecoration( color: Colors.transparent, - border: Border.all(color: MyColors.darkPrimaryColor, width: 2), - borderRadius: const BorderRadius.all(Radius.circular(8)), + border: Border.all( + color: MyColors.darkPrimaryColor, + width: 2), + borderRadius: const BorderRadius.all( + Radius.circular(8)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ const Icon( Icons.place_outlined, @@ -163,14 +179,24 @@ class DefineBranchPage extends StatelessWidget { SizedBox( width: double.infinity, child: Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20), + padding: + const EdgeInsets.only(left: 20, right: 20, bottom: 20), child: ShowFillButton( - title: branchData != null ? (branchData!.id == null ? LocaleKeys.createBranch.tr() : LocaleKeys.updateBranch.tr()) : LocaleKeys.createBranch.tr(), + title: branchData != null + ? (branchData!.id == null + ? LocaleKeys.createBranch.tr() + : LocaleKeys.updateBranch.tr()) + : LocaleKeys.createBranch.tr(), onPressed: () async { if (branchData == null) { Utils.showLoading(context); - MResponse res = - await model.createBranch(model.branchName, model.branchDescription, model.cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); + MResponse res = await model.createBranch( + model.branchName, + model.branchDescription, + model.cityId.toString(), + model.address, + model.latitude.toString(), + model.longitude.toString()); Utils.hideLoading(context); if (res.messageStatus == 1) { Utils.showToast(LocaleKeys.branch_created.tr()); @@ -182,7 +208,13 @@ class DefineBranchPage extends StatelessWidget { } else { Utils.showLoading(context); MResponse res = await model.updateBranch( - branchData!.id ?? 0, model.branchName, model.branchDescription, model.cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); + branchData!.id ?? 0, + model.branchName, + model.branchDescription, + model.cityId.toString(), + model.address, + model.latitude.toString(), + model.longitude.toString()); Utils.hideLoading(context); if (res.messageStatus == 1) { Utils.showToast(LocaleKeys.branch_updated.tr()); diff --git a/lib/views/settings/define_license_page.dart b/lib/views/settings/define_license_page.dart index 7c4bec7..84b7650 100644 --- a/lib/views/settings/define_license_page.dart +++ b/lib/views/settings/define_license_page.dart @@ -8,7 +8,8 @@ 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/general_models/m_response.dart'; import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/AppPermissionHandler.dart'; +import 'package:mc_common_app/utils/app_permission_handler.dart'; + import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; @@ -130,7 +131,7 @@ class _DefineLicensePageState extends State { maxLines: 3, isBackgroundEnabled: true, ), - if (((model.document?.data![index].documentUrl ?? "").toString().isNotEmpty)) + if ((model.document?.data![index].documentUrl ?? "").toString().isNotEmpty) Column( children: [ 8.height, @@ -144,7 +145,9 @@ class _DefineLicensePageState extends State { InkWell( onTap: () async { bool isPermissionsAvailable = await requestPermissionGranted(context, Permission.storage); - if (isPermissionsAvailable) model.selectFile(index); + if (isPermissionsAvailable) { + model.selectFile(context,index); + } }, child: Container( width: double.infinity, diff --git a/lib/views/settings/schedule/add_schedules_page.dart b/lib/views/settings/schedule/add_schedules_page.dart index 63cee01..645efa1 100644 --- a/lib/views/settings/schedule/add_schedules_page.dart +++ b/lib/views/settings/schedule/add_schedules_page.dart @@ -1,4 +1,3 @@ - import 'package:car_provider_app/view_models/schedule_view_model.dart'; import 'package:car_provider_app/views/settings/schedule/widgets/chips_picker_item.dart'; import 'package:car_provider_app/views/settings/schedule/widgets/select_days_sheet.dart'; @@ -10,6 +9,7 @@ import 'package:mc_common_app/models/appointments_models/schedule_model.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/date_helper.dart'; +import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; @@ -19,15 +19,24 @@ import 'package:mc_common_app/widgets/bottom_sheet.dart'; class AddSchedulesPage extends StatelessWidget { late ScheduleVM mModel; - String name = "", startDate = "", endDate = "", startTime = "", endTime = "", slotsTime = "", appointmentPerSlot = "", servicesGroupID = ""; + String name = "", + startDate = "", + endDate = "", + startTime = "", + endTime = "", + slotsTime = "", + appointmentPerSlot = "", + servicesGroupID = ""; late ScheduleData scheduleData; AddSchedulesPage({Key? key}) : super(key: key); setEditData() { name = scheduleData.scheduleName ?? ""; - startDate = DateHelper.formatAsYearMonthDay(scheduleData.fromDate ?? DateTime.now()); - endDate = DateHelper.formatAsYearMonthDay(scheduleData.toDate ?? DateTime.now()); + startDate = DateHelper.formatAsYearMonthDay( + scheduleData.fromDate ?? DateTime.now()); + endDate = + DateHelper.formatAsYearMonthDay(scheduleData.toDate ?? DateTime.now()); startTime = scheduleData.startTime ?? ""; endTime = scheduleData.endTime ?? ""; slotsTime = scheduleData.slotDurationMinute.toString(); @@ -35,7 +44,9 @@ class AddSchedulesPage extends StatelessWidget { // mModel.selectedServicesItems.clear(); scheduleData.scheduleServices?.forEach((element) { - mModel.selectedServicesItems.add(PickerItem(id: element.providerServiceId ?? 0, title: element.providerServiceName ?? "")); + mModel.selectedServicesItems.add(PickerItem( + id: element.providerServiceId ?? 0, + title: element.serviceDescription ?? "")); }); mModel.selectedDaysItems.clear(); scheduleData.weeklyOffDays?.forEach((element) { @@ -134,7 +145,7 @@ class AddSchedulesPage extends StatelessWidget { ), 8.height, ChipsPickerItem( - hint: 'Days', + hint: 'Off Days', itemsList: [...model.selectedDaysItems], onClick: () { showMyBottomSheet( @@ -179,7 +190,12 @@ class AddSchedulesPage extends StatelessWidget { isNeedClickAll: true, onTap: () async { TimeOfDay _startTime = TimeOfDay.now(); - if (startTime.isNotEmpty) _startTime = TimeOfDay(hour: int.parse(startTime.split(":")[0]), minute: int.parse(startTime.split(":")[1])); + if (startTime.isNotEmpty) + _startTime = TimeOfDay( + hour: + int.parse(startTime.split(":")[0]), + minute: + int.parse(startTime.split(":")[1])); endTime = await Utils.pickTime( context, initialTime: _startTime, @@ -315,12 +331,16 @@ class AddSchedulesPage extends StatelessWidget { Utils.hideLoading(context); if (servicesResponse.messageStatus == 1) { Utils.showToast("Successfully schedule created"); + context.read().getSchedules(scheduleData.branchId ?? ""); + pop(context); } else { - Utils.showToast("Something went wrong while adding services in schedule"); + Utils.showToast(servicesResponse.message ?? ""); + context.read().getSchedules(scheduleData.branchId ?? ""); + pop(context); } } else { Utils.hideLoading(context); - Utils.showToast("Something went wrong"); + Utils.showToast(scheduleResponse.message??""); } } @@ -362,8 +382,11 @@ class AddSchedulesPage extends StatelessWidget { Utils.hideLoading(context); if (servicesResponse.messageStatus == 1) { Utils.showToast("Successfully schedule updated"); + context.read().getSchedules(scheduleData.branchId ?? ""); + pop(context); } else { - Utils.showToast("Something went wrong while adding services in schedule"); + Utils.showToast( + "Something went wrong while adding services in schedule"); } } else { Utils.hideLoading(context); diff --git a/lib/views/settings/schedule/schedules_list_page.dart b/lib/views/settings/schedule/schedules_list_page.dart index f4f0b5e..ab7449a 100644 --- a/lib/views/settings/schedule/schedules_list_page.dart +++ b/lib/views/settings/schedule/schedules_list_page.dart @@ -58,7 +58,10 @@ class _SchedulesListPageState extends State { Row( children: [ Expanded( - child: value.schedule!.data![index].scheduleName.toString().toText( + child: value.schedule!.data![index] + .scheduleName + .toString() + .toText( fontSize: 16, isBold: true, ), @@ -71,33 +74,81 @@ class _SchedulesListPageState extends State { height: 16, ), ).onPress(() { - value.schedule!.data![index].branchId = widget.branchId ?? ""; - navigateWithName(context, ProviderAppRoutes.addSchedule, arguments: value.schedule!.data![index]); + value.schedule!.data![index] + .branchId = widget.branchId ?? ""; + navigateWithName(context, + ProviderAppRoutes.addSchedule, + arguments: + value.schedule!.data![index]); }), ], - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, ), 12.height, - showItem("Start Date:", DateHelper.formatAsDayMonthYear(value.schedule!.data![index].fromDate)), - showItem("End Date:", DateHelper.formatAsDayMonthYear(value.schedule!.data![index].toDate)), - showItem("Off Days:", DateHelper.formatAsDayMonthYear(value.schedule!.data![index].fromDate)), - showItem("Shift Start Time:", value.schedule!.data![index].startTime ?? ""), - showItem("Shift End Time:", value.schedule!.data![index].startTime ?? ""), - showItem("Slots Time:", value.schedule!.data![index].slotDurationMinute.toString() + " Mins"), - showItem("Appointments Per Slot:", value.schedule!.data![index].perSlotAppointment.toString()), - showItem("Off Days", offDays(value.schedule!.data![index])), + showItem( + "Start Date:", + DateHelper.formatAsDayMonthYear(value + .schedule!.data![index].fromDate)), + showItem( + "End Date:", + DateHelper.formatAsDayMonthYear(value + .schedule!.data![index].toDate)), + showItem( + "Off Days:", + DateHelper.formatAsDayMonthYear(value + .schedule!.data![index].fromDate)), + showItem( + "Shift Start Time:", + value.schedule!.data![index] + .startTime ?? + ""), + showItem( + "Shift End Time:", + value.schedule!.data![index] + .startTime ?? + ""), + showItem( + "Slots Time:", + value.schedule!.data![index] + .slotDurationMinute + .toString() + + " Mins"), + showItem( + "Appointments Per Slot:", + value.schedule!.data![index] + .perSlotAppointment + .toString()), + showItem("Off Days", + offDays(value.schedule!.data![index])), 12.height, - "Services:".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), + "Services:".toText( + fontSize: 12, + isBold: true, + color: MyColors.lightTextColor), Column( - children: value.schedule!.data![index].scheduleServices! - .map((element) => Container(child: element.providerServiceName.toString().toText(fontSize: 12, isBold: true))) + crossAxisAlignment: + CrossAxisAlignment.start, + children: value.schedule!.data![index] + .scheduleServices! + .map( + (element) => Container( + child: element.serviceDescription + .toString() + .toText( + fontSize: 12, + isBold: true, + ), + ), + ) .toList(), - crossAxisAlignment: CrossAxisAlignment.start, ) ], - ).toWhiteContainer(width: double.infinity, allPading: 12); + ).toWhiteContainer( + width: double.infinity, allPading: 12); }, - separatorBuilder: (BuildContext context, int index) { + separatorBuilder: + (BuildContext context, int index) { return 12.height; }, padding: const EdgeInsets.all(20), @@ -111,7 +162,8 @@ class _SchedulesListPageState extends State { maxWidth: double.infinity, margin: const EdgeInsets.all(20), onPressed: () { - navigateWithName(context, ProviderAppRoutes.addSchedule, arguments: ScheduleData(branchId: widget.branchId ?? "")); + navigateWithName(context, ProviderAppRoutes.addSchedule, + arguments: ScheduleData(branchId: widget.branchId ?? "")); }, ), ], @@ -123,7 +175,8 @@ class _SchedulesListPageState extends State { String offDays(ScheduleData scheduleData) { String offDays = ""; for (int i = 0; i < scheduleData.weeklyOffDays!.length; i++) { - offDays = offDays + initDaysList[scheduleData.weeklyOffDays![i].dayNumber! - 1].title; + offDays = offDays + + initDaysList[scheduleData.weeklyOffDays![i].dayNumber! - 1].title; if (i != scheduleData.weeklyOffDays!.length - 1) { offDays = offDays + " , "; } @@ -134,7 +187,8 @@ class _SchedulesListPageState extends State { Widget showItem(String title, String value) { return Row( children: [ - title.toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), + title.toText( + fontSize: 12, isBold: true, color: MyColors.lightTextColor), 4.width, value.toText(fontSize: 12, isBold: true), ], diff --git a/lib/views/settings/services/create_item_page.dart b/lib/views/settings/services/create_item_page.dart index 252a216..b5ce762 100644 --- a/lib/views/settings/services/create_item_page.dart +++ b/lib/views/settings/services/create_item_page.dart @@ -7,7 +7,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/services_models/item_model.dart'; import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/AppPermissionHandler.dart'; +import 'package:mc_common_app/utils/app_permission_handler.dart'; import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; @@ -130,7 +130,7 @@ class _CreateItemPageState extends State { onTap: () async { bool isPermissionsAvailable = await requestPermissionGranted(context, Permission.storage); if (isPermissionsAvailable && model != null) { - itemImage = await model!.selectFile() ?? ""; + itemImage = await model!.selectFile(context) ?? ""; setState(() {}); } }, diff --git a/lib/views/settings/services/create_services_page3.dart b/lib/views/settings/services/create_services_page3.dart index c7554d6..a9d0ddc 100644 --- a/lib/views/settings/services/create_services_page3.dart +++ b/lib/views/settings/services/create_services_page3.dart @@ -1,4 +1,3 @@ - import 'package:car_provider_app/generated/locale_keys.g.dart'; import 'package:car_provider_app/view_models/service_view_model.dart'; import 'package:car_provider_app/views/settings/services/services_list_page.dart'; @@ -29,20 +28,26 @@ class CreateServicesPage3 extends StatelessWidget { String chargersPerKm = "0"; int? categoryId; int? serviceId = -1; + DropValue? category; + DropValue? service; @override Widget build(BuildContext context) { ServiceVM serviceVM = context.read(); if (branchModel!.categoryId == null) { - serviceVM.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); + serviceVM.fetchBranchCategory( + EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); } else { - isAppointmentAvailable = branchModel?.serviceProviderService?.isAllowAppointment ?? false; + isAppointmentAvailable = + branchModel?.serviceProviderService?.isAllowAppointment ?? false; // isHomeAppointmentAvailable=branchModel.serviceProviderService. - serviceRage = branchModel?.serviceProviderService?.customerLocationRange ?? 0; + serviceRage = + branchModel?.serviceProviderService?.customerLocationRange ?? 0; if (serviceRage > 0) { isHomeAppointmentAvailable = true; } - chargersPerKm = branchModel?.serviceProviderService?.rangePricePerKm ?? "0"; + chargersPerKm = + branchModel?.serviceProviderService?.rangePricePerKm ?? "0"; serviceId = branchModel?.serviceProviderService?.serviceId ?? -1; } return Scaffold( @@ -67,7 +72,8 @@ class CreateServicesPage3 extends StatelessWidget { fontWeight: FontWeight.bold, ), ).toContainer( - padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + padding: const EdgeInsets.only( + left: 8, right: 8, bottom: 12, top: 12), backgroundColor: MyColors.textFieldColor, borderRadius: 0, width: double.infinity, @@ -81,34 +87,44 @@ class CreateServicesPage3 extends StatelessWidget { fontWeight: FontWeight.bold, ), ).toContainer( - padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + padding: const EdgeInsets.only( + left: 8, right: 8, bottom: 12, top: 12), backgroundColor: MyColors.textFieldColor, borderRadius: 0, width: double.infinity, ) - : (branchModel!.categoryId == null && model.categoryDropList.isNotEmpty) + : (branchModel!.categoryId == null && + model.categoryDropList.isNotEmpty) ? DropdownField( (DropValue value) async { categoryId = value.id; + category = value; + service = null; serviceId = -1; isAppointmentAvailable = false; isHomeAppointmentAvailable = false; - model.fetchServicesByCategoryId(value.id.toString()); + model.fetchServicesByCategoryId( + value.id.toString()); }, + dropdownValue: category, list: model.categoryDropList, - hint: LocaleKeys.selectServiceCategory.tr(), + hint: + LocaleKeys.selectServiceCategory.tr(), ) : const CircularProgressIndicator(), 12.height, branchModel!.serviceProviderService != null ? Text( - branchModel!.serviceProviderService!.serviceDescription ?? "N/A", + branchModel!.serviceProviderService! + .serviceDescription ?? + "N/A", style: const TextStyle( fontSize: 12, fontWeight: FontWeight.bold, ), ).toContainer( - padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + padding: const EdgeInsets.only( + left: 8, right: 8, bottom: 12, top: 12), backgroundColor: MyColors.textFieldColor, borderRadius: 0, width: double.infinity, @@ -117,10 +133,12 @@ class CreateServicesPage3 extends StatelessWidget { ? DropdownField( (DropValue value) { serviceId = value.id; + service = value; isAppointmentAvailable = false; isHomeAppointmentAvailable = false; model.setState(ViewState.idle); }, + dropdownValue: service, list: model.servicesDropList, hint: LocaleKeys.defineServices.tr(), ) @@ -135,7 +153,8 @@ class CreateServicesPage3 extends StatelessWidget { CheckBoxWithTitleDescription( isSelected: isAppointmentAvailable, title: 'Available for appointment', - description: 'This option will allow customer to book appointment for these services', + description: + 'This option will allow customer to book appointment for these services', onSelection: (bool v) { isAppointmentAvailable = v; model.setState(ViewState.idle); @@ -145,7 +164,8 @@ class CreateServicesPage3 extends StatelessWidget { CheckBoxWithTitleDescription( isSelected: isHomeAppointmentAvailable, title: 'Allow home services', - description: 'This option will allow customer to book appointment at their desired location', + description: + 'This option will allow customer to book appointment at their desired location', onSelection: (bool v) { isHomeAppointmentAvailable = v; model.setState(ViewState.idle); @@ -158,13 +178,18 @@ class CreateServicesPage3 extends StatelessWidget { TxtField( hint: "Home Services Range", keyboardType: TextInputType.number, - value: serviceRage == 0 ? null : serviceRage.toString(), + value: serviceRage == 0 + ? null + : serviceRage.toString(), postfixWidget: Row( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ - "KM".toText(color: MyColors.lightTextColor), + "KM".toText( + color: MyColors.lightTextColor), ], ), onChanged: (v) { @@ -179,7 +204,9 @@ class CreateServicesPage3 extends StatelessWidget { TxtField( hint: "Charges per Kilometer", keyboardType: TextInputType.number, - value: chargersPerKm == "0.0" ? null : chargersPerKm, + value: chargersPerKm == "0.0" + ? null + : chargersPerKm, onChanged: (v) { if (v.isNotEmpty) { chargersPerKm = v; diff --git a/lib/views/subscriptions/my_subscritions_page.dart b/lib/views/subscriptions/my_subscritions_page.dart index 7b2ac1f..ed0a0ca 100644 --- a/lib/views/subscriptions/my_subscritions_page.dart +++ b/lib/views/subscriptions/my_subscritions_page.dart @@ -1,11 +1,19 @@ -import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; +import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:car_provider_app/views/subscriptions/sheet/select_package_sheet.dart'; import 'package:car_provider_app/views/subscriptions/widget/subscriptions_card.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/view_models/payment_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.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'; import 'package:provider/provider.dart'; class MySubscriptionsPage extends StatelessWidget { @@ -13,7 +21,8 @@ class MySubscriptionsPage extends StatelessWidget { @override Widget build(BuildContext context) { - context.read().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? ""); + context.read().getMySubscriptions( + AppState().getUser.data?.userInfo?.providerId.toString() ?? ""); return Scaffold( appBar: const CustomAppBar( title: "My Subscriptions", @@ -21,33 +30,70 @@ class MySubscriptionsPage extends StatelessWidget { body: SizedBox( width: double.infinity, height: double.infinity, - child: Consumer(builder: (context, model, _) { - return model.state == ViewState.busy - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - child: Column( - children: [ - 21.height, - ListView.separated( - itemBuilder: (BuildContext context, int index) { - return SubscriptionsCard( - model.allSubscriptions.data![index], - isSubscribed: model.allSubscriptions.data![index].isSubscribed ?? false, - backgroundColor: MyColors.darkIconColor, - ); - }, - separatorBuilder: (BuildContext context, int index) { - return 21.height; - }, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: model.allSubscriptions.data!.length, - ), - 21.height, - ], - ), - ); - }), + child: Column( + children: [ + Expanded( + child: Consumer(builder: (context, model, _) { + return model.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: Column( + children: [ + 21.height, + ListView.separated( + itemBuilder: (BuildContext context, int index) { + return SubscriptionsCard( + model.allSubscriptions.data![index], + isSubscribed: model.allSubscriptions + .data![index].isSubscribed ?? + false, + backgroundColor: MyColors.darkIconColor, + onRenewSubscriptionClick: () { + context + .read() + .updateOrderProviderSubscriptionId( + id: model.allSubscriptions + .data![index].id ?? + 0); + navigateWithName( + context, + AppRoutes.paymentMethodsView, + arguments: PaymentTypes.subscription, + ); + }, + ).onPress( + () { + showMyBottomSheet(context, + child: const SelectPackageSheet()); + }, + ); + }, + separatorBuilder: + (BuildContext context, int index) { + return 21.height; + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: model.allSubscriptions.data!.length, + ), + 21.height, + ], + ), + ); + }), + ), + 21.height, + ShowFillButton( + title: "Modify Package", + maxWidth: double.infinity, + margin: const EdgeInsets.symmetric(horizontal: 21), + onPressed: () { + navigateWithName(context, ProviderAppRoutes.subscriptionsPage); + }, + ), + 21.height, + ], + ), ), ); } diff --git a/lib/views/subscriptions/sheet/degrage_package_sheet.dart b/lib/views/subscriptions/sheet/degrage_package_sheet.dart new file mode 100644 index 0000000..f6ceaf0 --- /dev/null +++ b/lib/views/subscriptions/sheet/degrage_package_sheet.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; + +class DegradePackageSheet extends StatelessWidget { + const DegradePackageSheet({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "Deactivate the branches & users".toText( + fontSize: 18, + isBold: true, + ), + "To select this subscription you need to deactivate your branches and users as this package only supports 1 branch and 2 users per branch. You can reactivate these branches later after upgrading the package" + .toText( + fontSize: 14, + color: MyColors.lightTextColor, + ), + 12.height, + showBranchList(), + 12.height, + ], + ), + ); + } + + Widget showBranchList() { + return ListView.separated( + itemBuilder: (context, index) { + return Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + customCheckBox(true), + 12.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Olaya Branch".toText( + fontSize: 16, + isBold: true, + ), + "3 Users".toText( + fontSize: 10, + color: MyColors.lightTextColor, + ), + ], + ), + ), + IconButton( + onPressed: () {}, + icon: const Icon( + Icons.keyboard_arrow_down, + ), + ) + ], + ), + showUser("Mirza"), + 12.height, + showUser("Shafique"), + ], + ).toContainer( + isShadowEnabled: true, + borderRadius: 0, + paddingAll: 12, + ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: 2, + ); + } + + Widget showUser(String user) { + return Row( + children: [ + const SizedBox( + width: 24, + ), + customCheckBox(false), + 12.width, + user.toText(fontSize: 14), + ], + ); + } + + Widget customCheckBox(bool isChecked) { + return SizedBox( + height: 18, + width: 18, + child: isChecked + ? const Icon( + Icons.done, + color: Colors.white, + size: 14, + ) + : const SizedBox(), + ).toContainer( + isEnabledBorder: true, + paddingAll: 0, + borderRadius: 0, + borderWidget: 1, + borderColor: MyColors.primaryColor, + backgroundColor: isChecked ? MyColors.primaryColor : Colors.transparent, + ); + } +} diff --git a/lib/views/subscriptions/sheet/downgrade_data_sheet.dart b/lib/views/subscriptions/sheet/downgrade_data_sheet.dart new file mode 100644 index 0000000..3129c22 --- /dev/null +++ b/lib/views/subscriptions/sheet/downgrade_data_sheet.dart @@ -0,0 +1,294 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.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/general_models/m_response.dart'; +import 'package:mc_common_app/models/subscriptions_models/branch_user_selection_model.dart'; +import 'package:mc_common_app/models/subscriptions_models/subscription_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/utils/utils.dart'; +import 'package:mc_common_app/view_models/payment_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; +import 'package:mc_common_app/views/payments/payment_methods_view.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class DowngradeDataSheet extends StatefulWidget { + Subscription subscription; + + DowngradeDataSheet(this.subscription, {super.key}); + + @override + State createState() => _DowngradeDataSheetState(); +} + +class _DowngradeDataSheetState extends State { + @override + void initState() { + super.initState(); + context.read().getSPBranchUser_Get(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height / 1.2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(12), + child: Column( + children: [ + "Deactivate the branches & users".toText( + fontSize: 19, + isBold: true, + ), + 8.height, + "To select this subscription you need to deactivate your branches and users as this package only supports 1 branch and 2 users per branch. You can reactivate these branches later after upgrading the package" + .toText( + fontSize: 14, + color: MyColors.textColor, + ), + ], + ), + ), + Expanded( + child: Consumer( + builder: (BuildContext context, model, Widget? child) { + return Column( + children: [ + Expanded( + child: model.branchSelectionList == null + ? const Center(child: CircularProgressIndicator()) + : ListView.separated( + itemBuilder: (context, index) { + return showBranchItem( + model, model.branchSelectionList![index]); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + padding: const EdgeInsets.all(12), + itemCount: model.branchSelectionList?.length ?? 0, + ), + ), + ShowFillButton( + title: "Next", + maxWidth: double.infinity, + margin: const EdgeInsets.all(12), + onPressed: () async { + List listOfBranches = []; + List listOfUsers = []; + for (var element in model.branchSelectionList!) { + if (element.isSelected) { + listOfBranches.add(element.branchId); + } else { + for (var element in element.usersList) { + if (element.isSelected) { + listOfUsers.add(element.userId); + } + } + } + } + print("opoewww"); + print(jsonEncode(listOfBranches)); + if (listOfBranches.isNotEmpty || + listOfUsers.isNotEmpty) { + navigateTo( + context, + PaymentMethodsView( + paymentType: PaymentTypes.subscription, + onTempContinue: () async { + Utils.showLoading(context); + MResponse response = + await model.payForSubscription( + widget.subscription.id!, + true, + false, + widget.subscription.price.toString(), + isDegrade: true, + listOfBranches: listOfBranches, + listOfUsers: listOfUsers, + ); + Utils.hideLoading(context); + + if (response.messageStatus == 1) { + if(response.message!.contains("Your current sub-users are not")){ + Utils.showToast(response.message.toString()); + context.read().getMySubscriptions( + AppState() + .getUser + .data + ?.userInfo + ?.providerId + .toString() ?? + ""); + pop(context); + return false; + }else{ + context + .read() + .updateOrderProviderSubscriptionId( + id: response.data); + + // Utils.showToast( + // "Subscriptions is successfully updated"); + return true; + } + + } else { + Utils.showToast(response.message.toString()); + context.read().getMySubscriptions( + AppState() + .getUser + .data + ?.userInfo + ?.providerId + .toString() ?? + ""); + return false; + } + }, + ), + ); + } + }, + ), + ], + ); + }, + ), + ), + ], + ), + ); + } + + Widget showBranchItem(SubscriptionsVM viewModel, BranchSelectionModel model) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + customCheckBox(model.isSelected).onPress(() { + model.isSelected = !model.isSelected; + if (model.isSelected) { + for (var element in model.usersList) { + element.isSelected = true; + } + } else { + for (var element in model.usersList) { + element.isSelected = false; + } + } + model.isOpend = true; + viewModel.setState(ViewState.idle); + }), + 12.width, + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: double.infinity, + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + model.branchName.toText( + fontSize: 18, + isBold: true, + ), + ("${model.usersList.length} Users").toText( + fontSize: 10, + color: MyColors.lightTextColor, + ) + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + model.isOpend + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded, + ), + ], + ), + ], + ), + ), + if (model.isOpend) 12.height, + if (model.isOpend) + ListView.separated( + itemBuilder: (context, index) { + return Row( + children: [ + customCheckBox(model.usersList[index].isSelected), + 8.width, + model.usersList[index].userName.toText( + fontSize: 14, + ), + ], + ).onPress(() { + // for (int i = 0; i < model.usersList.length; i++) { + // if (i != index) { + // model.usersList[index].isSelected = false; + // } + // } + model.usersList[index].isSelected = + !model.usersList[index].isSelected; + viewModel.setState(ViewState.idle); + }); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: model.usersList.length, + ), + ], + ).onPress(() { + model.isOpend = !model.isOpend; + viewModel.setState(ViewState.idle); + }), + ) + ], + ).toWhiteContainer( + width: double.infinity, + pading: const EdgeInsets.all(12), + ); + } + + Widget customCheckBox(bool isChecked) { + return SizedBox( + height: 18, + width: 18, + child: isChecked + ? const Icon( + Icons.done, + color: Colors.white, + size: 14, + ) + : const SizedBox(), + ).toContainer( + isEnabledBorder: true, + paddingAll: 0, + borderRadius: 0, + borderWidget: 1, + borderColor: MyColors.primaryColor, + backgroundColor: isChecked ? MyColors.primaryColor : Colors.transparent, + ); + } +} diff --git a/lib/views/subscriptions/sheet/select_package_sheet.dart b/lib/views/subscriptions/sheet/select_package_sheet.dart new file mode 100644 index 0000000..266c84d --- /dev/null +++ b/lib/views/subscriptions/sheet/select_package_sheet.dart @@ -0,0 +1,89 @@ +import 'package:car_provider_app/views/subscriptions/sheet/degrage_package_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/bottom_sheet.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; + +class SelectPackageSheet extends StatelessWidget { + const SelectPackageSheet({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "When do you want to upgrade".toText( + fontSize: 19, + isBold: true, + ), + 12.height, + showPackage(), + 12.height, + showPackage(), + 12.height, + ShowFillButton( + title: "Upgrade", + maxWidth: double.infinity, + onPressed: () { + showMyBottomSheet(context, child: const DegradePackageSheet()); + }, + ), + 12.height, + ], + ), + ); + } + + Widget showPackage() { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Checkbox( + value: false, + onChanged: (v) {}, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "Now".toText( + fontSize: 16, + isBold: true, + ), + "Your subscription will upgrade now. Affecting from 23 January, 2024" + .toText( + fontSize: 12, + color: MyColors.lightTextColor, + ), + 12.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "175".toText( + fontSize: 26, + isBold: true, + ), + 2.width, + "SAR".toText( + color: MyColors.lightTextColor, + fontSize: 16, + ), + ], + ) + ], + ), + ) + ], + ).toContainer(isShadowEnabled: true); + } +} diff --git a/lib/views/subscriptions/sheet/upgrade_package_sheet.dart b/lib/views/subscriptions/sheet/upgrade_package_sheet.dart new file mode 100644 index 0000000..cd5d009 --- /dev/null +++ b/lib/views/subscriptions/sheet/upgrade_package_sheet.dart @@ -0,0 +1,199 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.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/general_models/m_response.dart'; +import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/date_helper.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/payment_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; +import 'package:mc_common_app/views/payments/payment_methods_view.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class UpgradePackageSheet extends StatefulWidget { + Subscription subscription; + + UpgradePackageSheet(this.subscription, {super.key}); + + @override + State createState() => _UpgradePackageSheetState(); +} + +class _UpgradePackageSheetState extends State { + bool isNowSelected = true; + String price = "0"; + + @override + void initState() { + // TODO: implement initState + super.initState(); + calculateUpgradePrice(); + } + + calculateUpgradePrice() { + context.read().calculationUpgradePrice( + AppState().getUser.data?.userInfo?.providerId.toString() ?? "", + widget.subscription.id.toString(), + ); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 4), + child: Consumer(builder: (context, model, _) { + if (model.state == ViewState.busy) { + return SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height / 2, + child: const Center(child: CircularProgressIndicator()), + ); + } else { + if (isNowSelected) { + price = model.newPrice.toString(); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "When do you want to upgrade".toText( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + 12.height, + packageItem( + "Now", + ("Your subscription will upgrade now. Affecting from ${DateHelper.formatAsLongDate(widget.subscription.dateEnd!)}"), + model.newPrice.toString(), + isNowSelected, + ).onPress(() { + setState(() { + price = model.newPrice.toString(); + isNowSelected = true; + }); + }), + 6.height, + packageItem( + "Upgrade after current expiry", + ("Your subscription will upgrade after you current subscription will end. Affecting from 27 January, 2024 ${DateHelper.formatAsLongDate(widget.subscription.dateEnd!)}"), + widget.subscription.price.toString(), + isNowSelected ? false : true, + ).onPress(() { + price = widget.subscription.price.toString(); + setState(() { + isNowSelected = false; + }); + }), + 12.height, + ShowFillButton( + title: "Upgrade", + maxWidth: double.infinity, + onPressed: () async { + navigateTo( + context, + PaymentMethodsView( + paymentType: PaymentTypes.subscription, + onTempContinue: () async { + Utils.showLoading(context); + MResponse mResponse = await model.payForSubscription( + widget.subscription.id!, + isNowSelected, + false, + price); + Utils.hideLoading(context); + if (mResponse.messageStatus == 1) { + context + .read() + .updateOrderProviderSubscriptionId( + id: mResponse.data); + + // Utils.showToast( + // "Subscriptions is successfully updated"); + return true; + } else { + Utils.showToast(mResponse.message.toString()); + return false; + } + }, + ), + ); + }, + ), + ], + ); + } + }), + ); + } + + Widget packageItem( + String title, String description, String price, bool isSelected) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Icon( + Icons.done, + size: 14, + color: Colors.white, + ).toContainer( + isEnabledBorder: true, + backgroundColor: + isSelected ? MyColors.primaryColor : Colors.transparent, + borderColor: MyColors.primaryColor, + borderWidget: 1, + borderRadius: 0, + paddingAll: 2, + ), + 12.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + title.toText( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + 4.height, + if (widget.subscription.dateEnd != null) + description.toText( + fontSize: 12, + color: MyColors.lightTextColor, + ), + 10.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + price.toText(fontSize: 24, isBold: true), + 2.width, + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: "SAR".toText( + fontSize: 16, + isBold: true, + color: MyColors.lightTextColor), + ), + ], + ) + ], + ), + ), + ], + ).toContainer( + isShadowEnabled: true, + paddingAll: 16, + borderRadius: 0, + borderColor: isSelected ? MyColors.primaryColor : Colors.transparent, + isEnabledBorder: true, + borderWidget: 2, + ); + } +} diff --git a/lib/views/subscriptions/subscriptions_page.dart b/lib/views/subscriptions/subscriptions_page.dart index bbfa64b..2426a92 100644 --- a/lib/views/subscriptions/subscriptions_page.dart +++ b/lib/views/subscriptions/subscriptions_page.dart @@ -1,10 +1,17 @@ -import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; + +import 'package:car_provider_app/views/subscriptions/sheet/downgrade_data_sheet.dart'; +import 'package:car_provider_app/views/subscriptions/sheet/upgrade_package_sheet.dart'; import 'package:car_provider_app/views/subscriptions/widget/subscriptions_card.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/models/subscriptions_models/subscription_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/view_models/payment_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; +import 'package:mc_common_app/widgets/bottom_sheet.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/tab/menu_tabs.dart'; @@ -15,7 +22,10 @@ class SubscriptionsPage extends StatelessWidget { @override Widget build(BuildContext context) { - context.read().getAllAvailableSubscriptions(null); + context.read().getSubscriptionBySP( + AppState().getUser.data?.userInfo?.providerId.toString() ?? "", + true, + ); return Scaffold( appBar: const CustomAppBar( title: "Subscriptions", @@ -47,6 +57,21 @@ class SubscriptionsPage extends StatelessWidget { return SubscriptionsCard( model.tempSubscriptions[index], isSubscribed: model.tempSubscriptions[index].isSubscribed ?? false, + isMainPage: false, + onRenewSubscriptionClick: () { + // context.read().updateOrderProviderSubscriptionId(id: model.tempSubscriptions[index].id??0); + // navigateWithName( + // context, + // AppRoutes.paymentMethodsView, + // arguments: PaymentTypes.subscription, + // ); + if(model.tempSubscriptions[index].subscriptionTypeEnum==SubscriptionTypeEnum.upgrade){ + showMyBottomSheet(context, child: UpgradePackageSheet(model.tempSubscriptions[index])); + }else{ + showMyBottomSheet(context, child: DowngradeDataSheet(model.tempSubscriptions[index])); + } + + }, ); }, separatorBuilder: (BuildContext context, int index) { diff --git a/lib/views/subscriptions/widget/subscriptions_card.dart b/lib/views/subscriptions/widget/subscriptions_card.dart index bf4fb82..237c44f 100644 --- a/lib/views/subscriptions/widget/subscriptions_card.dart +++ b/lib/views/subscriptions/widget/subscriptions_card.dart @@ -1,129 +1,168 @@ - import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/date_helper.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; - class SubscriptionsCard extends StatelessWidget { Subscription subscription; bool isSubscribed; Color? backgroundColor; late Color textColor; + Function onRenewSubscriptionClick; + bool isMainPage; - SubscriptionsCard(this.subscription, {Key? key, this.isSubscribed = false, this.backgroundColor}) : super(key: key); + SubscriptionsCard(this.subscription, + {Key? key, + this.isSubscribed = false, + this.backgroundColor, + required this.onRenewSubscriptionClick, + this.isMainPage = true}) + : super(key: key); @override Widget build(BuildContext context) { textColor = backgroundColor == null ? Colors.black : Colors.white; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: subscription.name.toString().toText( - fontSize: 18, - color: textColor, - ), - ), - if (isSubscribed) - Row( - children: [ - Container( - color: MyColors.white, - padding: const EdgeInsets.all(2), - child: const Icon( - Icons.done, - size: 8, - color: MyColors.primaryColor, + return InkWell( + onTap: isSubscribed + ? null + : () { + onRenewSubscriptionClick(); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: subscription.name.toString().toText( + fontSize: 18, + color: textColor, ), - ).toCircle( - borderRadius: 122, - ), - 6.width, - "Subscribed".toText(color: Colors.white, isBold: true) - ], - ).toContainer( - backgroundColor: MyColors.primaryColor, - borderRadius: 20, - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 3, - ), - ) - ], - ), - 6.height, - showItem("Ads:", subscription.numberOfAds.toString()), - showItem("Users:", subscription.numberOfSubUsers.toString()), - showItem("Branches:", subscription.numberOfBranches.toString()), - 14.height, - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - subscription.price.toString().toText( - fontSize: 26, - isBold: true, - color: textColor, - ), - 2.width, - "${subscription.currency}/Month".toText( - color: MyColors.lightTextColor, - fontSize: 16, - ), - ], ), - ), - if (!isSubscribed) - Row( - children: [ - "Upgrade".toText( - fontSize: 14, - color: textColor, - ), - 4.width, - Icon( - Icons.arrow_forward, - size: 16, - color: textColor, - ) - ], - ) - ], - ), - if (isSubscribed) + // if (isSubscribed) + // Row( + // children: [ + // Container( + // color: MyColors.white, + // padding: const EdgeInsets.all(2), + // child: const Icon( + // Icons.done, + // size: 8, + // color: MyColors.primaryColor, + // ), + // ).toCircle( + // borderRadius: 122, + // ), + // 6.width, + // "Subscribed".toText(color: Colors.white, isBold: true) + // ], + // ).toContainer( + // backgroundColor: MyColors.primaryColor, + // borderRadius: 20, + // padding: const EdgeInsets.symmetric( + // horizontal: 6, + // vertical: 3, + // ), + // ) + if (!isMainPage) + if (subscription.subscriptionTypeEnum == + SubscriptionTypeEnum.current) + "Current Package".toText(color: MyColors.primaryColor,fontWeight: FontWeight.bold), + if (isMainPage) + "Upgrade".toText(color: Colors.white).toContainer( + backgroundColor: MyColors.primaryColor, + borderRadius: 30, + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 3, + ), + ) + ], + ), + 6.height, + showItem("Ads:", subscription.numberOfAds.toString()), + showItem("Users:", subscription.numberOfSubUsers.toString()), + showItem("Branches:", subscription.numberOfBranches.toString()), + 14.height, Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ - "Expires on ${DateHelper.formatAsDayMonthYear(subscription.dateEnd)}".toText( - fontSize: 14, - color: textColor, - ), - 6.width, - "Renew".toText( - color: MyColors.primaryColor, - fontSize: 14, - textDecoration: TextDecoration.underline, - isBold: true, + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + subscription.price.toString().toText( + fontSize: 26, + isBold: true, + color: textColor, + ), + 2.width, + "${subscription.currency}/Month".toText( + color: MyColors.lightTextColor, + fontSize: 16, + ), + ], + ), ), + if (!isMainPage) + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + (subscription.subscriptionTypeEnum == + SubscriptionTypeEnum.current) + ? "Renew".toText() + : (subscription.subscriptionTypeEnum)! + .getStringSubscriptionTypeEnum() + .toText(), + 6.width, + const Icon( + Icons.arrow_forward, + size: 16, + ) + ], + ), ], - ) - ], - ).toWhiteContainer( - width: double.infinity, - allPading: 12, - backgroundColor: backgroundColor, - margin: const EdgeInsets.symmetric( - horizontal: 21, + ), + // if (isSubscribed) + if (isMainPage) + Row( + children: [ + "Expires on ${DateHelper.formatAsDayMonthYear(subscription.dateEnd)}" + .toText( + fontSize: 14, + color: textColor, + ), + Row( + children: [ + 6.width, + "Renew".toText( + color: MyColors.primaryColor, + fontSize: 14, + textDecoration: TextDecoration.underline, + decorationColor: MyColors.primaryColor, + isBold: true, + ), + ], + ).onPress(() { + onRenewSubscriptionClick(); + }), + ], + ) + ], + ).toWhiteContainer( + width: double.infinity, + allPading: 12, + backgroundColor: backgroundColor, + margin: const EdgeInsets.symmetric( + horizontal: 21, + ), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 1f8061b..a0c8ba4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + # mc_common_app: ## git: https://gitlab.com/mirza.shafique/car_common_app.git # path: C:/Users/mirza.shafique/AndroidStudioProjects/mc_common_app