From a45980162de59f87d38a598dde93358244ca6b9d Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 31 Mar 2026 12:56:48 +0300 Subject: [PATCH] Added location option in region selection bottom sheet --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/core/app_state.dart | 2 +- .../appointment_via_region_viewmodel.dart | 12 ++ lib/generated/locale_keys.g.dart | 1 + .../region_list_widget.dart | 143 +++++++++++++++--- lib/presentation/contact_us/find_us_page.dart | 2 +- 7 files changed, 142 insertions(+), 24 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 23cdc3ce..e0ccd055 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1596,5 +1596,6 @@ "verifyInsurance": "التحقق من التأمين", "tests": "تحليل", "calendarPermissionAlert": "يرجى منح إذن الوصول إلى التقويم من إعدادات التطبيق لضبط تذكير تناول الدواء.", - "sortByLocation": "الترتيب حسب الموقع" + "sortByLocation": "الترتيب حسب الموقع", + "sortByNearestLocation": "فرز حسب الأقرب إلى موقعك" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 1373f9c8..661434c4 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1590,5 +1590,6 @@ "verifyInsurance": "Verify Insurance", "tests": "tests", "calendarPermissionAlert": "Please grant calendar access permission from app settings to set medication reminder.", - "sortByLocation": "Sort by location" + "sortByLocation": "Sort by location", + "sortByNearestLocation": "Sort by nearest to your location" } diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index b95b883f..7d3ab1a4 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -169,7 +169,7 @@ class AppState { ///this will be called if there is any problem in getting the user location void resetLocation() { userLong = 0.0; - userLong = 0.0; + userLat = 0.0; } setRatedVisible(bool value) { diff --git a/lib/features/my_appointments/appointment_via_region_viewmodel.dart b/lib/features/my_appointments/appointment_via_region_viewmodel.dart index c5dcaf62..10da4e3d 100644 --- a/lib/features/my_appointments/appointment_via_region_viewmodel.dart +++ b/lib/features/my_appointments/appointment_via_region_viewmodel.dart @@ -43,9 +43,20 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier { int hmgCount = 0; int hmcCount = 0; RegionBottomSheetType regionBottomSheetType = RegionBottomSheetType.FOR_REGION; + bool sortByLocation = false; AppointmentViaRegionViewmodel({required this.navigationService,required this.appState}); + void initSortByLocation() { + sortByLocation = (appState.userLat != 0.0) && (appState.userLong != 0.0); + notifyListeners(); + } + + void setSortByLocation(bool value) { + sortByLocation = value; + notifyListeners(); + } + void setSelectedRegionId(String? regionId) { selectedRegionId = regionId; notifyListeners(); @@ -122,6 +133,7 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier { setFacility(null); setBottomSheetType(RegionBottomSheetType.FOR_REGION); setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION); + sortByLocation = false; } void setHospitalModel(PatientDoctorAppointmentList? hospital) { diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index a28652d9..886e910b 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1591,5 +1591,6 @@ abstract class LocaleKeys { static const tests = 'tests'; static const calendarPermissionAlert = 'calendarPermissionAlert'; static const sortByLocation = 'sortByLocation'; + static const sortByNearestLocation = 'sortByNearestLocation'; } diff --git a/lib/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart b/lib/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart index 489ee8b7..76089b74 100644 --- a/lib/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart +++ b/lib/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart @@ -3,6 +3,9 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/location_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -14,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bot import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:lottie/lottie.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -33,6 +37,7 @@ class _RegionBottomSheetBodyState extends State { @override void initState() { scheduleMicrotask(() { + regionalViewModel.initSortByLocation(); if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER ) { myAppointmentsViewModel.getRegionMappedProjectList(); } else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) { @@ -110,30 +115,128 @@ class _RegionBottomSheetBodyState extends State { } else { return SizedBox( height: MediaQuery.of(context).size.height * 0.5, - child: ListView.separated( - itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0, - separatorBuilder: (_, __) { - return SizedBox( - height: 16.h, - ); - }, - itemBuilder: (_, index) { - String key = myAppointmentsVM.hospitalList?.registeredDoctorMap?.keys.toList()[index] ?? ''; - return RegionListItem( - title: key, - subTitle: "", - hmcCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}", - hmgCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}", - ).onPress(() { - regionalViewModel.setSelectedRegionId(key); - regionalViewModel.setDisplayListAndRegionHospitalList(myAppointmentsVM.hospitalList?.registeredDoctorMap![key]); - regionalViewModel.setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION); - }); - }, + child: Column( + children: [ + Consumer( + builder: (context, regionVM, _) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.location, iconColor: AppColors.greyTextColor, width: 24.h, height: 24.h), + SizedBox(width: 12.w), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true), + // SizedBox(height: 4.h), + LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + ], + ), + ], + ), + Switch( + value: regionVM.sortByLocation, + onChanged: (value) => _handleSortByLocationToggle(value), + activeThumbColor: AppColors.successColor, + activeTrackColor: AppColors.successColor.withValues(alpha: 0.15), + ), + ], + ), + ); + }, + ), + Expanded( + child: ListView.separated( + itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0, + separatorBuilder: (_, __) { + return SizedBox( + height: 16.h, + ); + }, + itemBuilder: (_, index) { + String key = myAppointmentsVM.hospitalList?.registeredDoctorMap?.keys.toList()[index] ?? ''; + return RegionListItem( + title: key, + subTitle: "", + hmcCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}", + hmgCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}", + ).onPress(() { + regionalViewModel.setSelectedRegionId(key); + regionalViewModel.setDisplayListAndRegionHospitalList(myAppointmentsVM.hospitalList?.registeredDoctorMap![key]); + regionalViewModel.setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION); + }); + }, + ), + ), + ], ), ); } }, ); } + + void _handleSortByLocationToggle(bool value) { + if (value) { + // User wants to sort by location — check permission & get location + final locationUtils = getIt.get(); + locationUtils.getLocation( + isShowConfirmDialog: true, + onSuccess: (latLng) { + regionalViewModel.setSortByLocation(true); + myAppointmentsViewModel.getRegionMappedProjectList(); + }, + onFailure: () { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: "Please grant location permission from app settings to see better results", + isShowActionButtons: true, + onCancelTap: () { + Navigator.of(context).pop(); + }, + onConfirmTap: () async { + Navigator.of(context).pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + regionalViewModel.setSortByLocation(false); + }, + onLocationDeniedForever: () { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: "Please grant location permission from app settings to see better results", + isShowActionButtons: true, + onCancelTap: () { + Navigator.of(context).pop(); + }, + onConfirmTap: () async { + Navigator.of(context).pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + regionalViewModel.setSortByLocation(false); + }, + ); + } else { + // User turned off sort by location — reset location & re-fetch + final appState = getIt.get(); + appState.resetLocation(); + regionalViewModel.setSortByLocation(false); + myAppointmentsViewModel.getRegionMappedProjectList(); + } + } } diff --git a/lib/presentation/contact_us/find_us_page.dart b/lib/presentation/contact_us/find_us_page.dart index 9091f74d..0cabbf2b 100644 --- a/lib/presentation/contact_us/find_us_page.dart +++ b/lib/presentation/contact_us/find_us_page.dart @@ -59,7 +59,7 @@ class FindUsPage extends StatelessWidget { children: [ LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true), SizedBox(height: 4.h), - "Sort the locations by nearest to your location".toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), ], ), const Spacer(),