Merge branch 'master' into faiz_dev

# Conflicts:
#	lib/core/utils/utils.dart
#	lib/presentation/book_appointment/laser/widgets/body_part_listing.dart
#	lib/widgets/buttons/custom_button.dart
#	lib/widgets/common_bottom_sheet.dart
#	lib/widgets/input_widget.dart
pull/86/head
faizatflutter 3 weeks ago
commit 21be3a2d06

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,3 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.99996 1.22925C3.53667 1.22925 0.729126 4.0368 0.729126 7.50008C0.729126 10.9634 3.53667 13.7709 6.99996 13.7709C10.4632 13.7709 13.2708 10.9634 13.2708 7.50008C13.2708 4.0368 10.4632 1.22925 6.99996 1.22925ZM9.74577 5.57923C9.97358 5.35142 9.97358 4.98207 9.74577 4.75427C9.51797 4.52646 9.14862 4.52646 8.92081 4.75427L7 6.67509L5.95409 5.62925C5.72628 5.40146 5.35693 5.40147 5.12913 5.62928C4.90133 5.8571 4.90135 6.22644 5.12916 6.45424L6.17504 7.50004L6.00415 7.67094C5.77634 7.89874 5.77634 8.26809 6.00415 8.49589C6.23195 8.7237 6.6013 8.7237 6.8291 8.49589L7.00002 8.32497L7.17076 8.49569C7.39857 8.72349 7.76792 8.72348 7.99571 8.49567C8.22351 8.26785 8.2235 7.89851 7.99569 7.67071L7.82498 7.50002L9.74577 5.57923Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 902 B

@ -735,6 +735,8 @@ class ApiConsts {
static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD
static String RCBaseUrl = 'https://rc.hmg.com/'; // RC API URL PROD
static String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
static num VERSION_ID = 18.9;
@ -764,6 +766,7 @@ class ApiConsts {
TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/';
break;
case AppEnvironmentTypeEnum.dev:
baseUrl = "https://uat.hmgwebservices.com/";
@ -773,6 +776,7 @@ class ApiConsts {
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/test/';
break;
case AppEnvironmentTypeEnum.uat:
baseUrl = "https://uat.hmgwebservices.com/";
@ -782,6 +786,7 @@ class ApiConsts {
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/test/';
break;
case AppEnvironmentTypeEnum.preProd:
@ -792,6 +797,7 @@ class ApiConsts {
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/';
break;
case AppEnvironmentTypeEnum.qa:
baseUrl = "https://uat.hmgwebservices.com/";
@ -801,6 +807,7 @@ class ApiConsts {
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/test/';
break;
case AppEnvironmentTypeEnum.staging:
baseUrl = "https://uat.hmgwebservices.com/";
@ -810,6 +817,7 @@ class ApiConsts {
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
RCBaseUrl = 'https://rc.hmg.com/test/';
break;
}
}
@ -841,7 +849,6 @@ class ApiConsts {
static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile';
static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus';
// static values for Api
static final double appVersionID = 18.7;
static final int appChannelId = 3;

@ -158,6 +158,7 @@ class AppAssets {
static const String call_ambulance_icon = '$svgBasePath/call_ambulance_icon.svg';
static const String nearest_er_icon = '$svgBasePath/nearest_er_icon.svg';
static const String rrt_icon = '$svgBasePath/rrt_icon.svg';
static const String waiting_time_clock = '$svgBasePath/waiting_time_clock.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';
@ -202,4 +203,8 @@ class AppAnimations {
static const String noData = '$lottieBasePath/Nodata.json';
static const String ripple = '$lottieBasePath/Ripple.json';
static const String pending_loading_animation = '$lottieBasePath/pending_loading_animation.json';
static const String ambulance = '$lottieBasePath/ambulance.json';
static const String ambulance_alert = '$lottieBasePath/ambulance_alert.json';
static const String rrt_ambulance = '$lottieBasePath/rrt_ambulance.json';
}

@ -9,6 +9,8 @@ import 'package:hmg_patient_app_new/features/book_appointments/book_appointments
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart';
@ -38,6 +40,7 @@ import 'package:hmg_patient_app_new/services/localauth_service.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart';
import 'package:http/http.dart';
import 'package:local_auth/local_auth.dart';
import 'package:logger/web.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -99,6 +102,7 @@ class AppDependencies {
getIt.registerLazySingleton<HabibWalletRepo>(() => HabibWalletRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MedicalFileRepo>(() => MedicalFileRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ImmediateLiveCareRepo>(() => ImmediateLiveCareRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<EmergencyServicesRepo>(() => EmergencyServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -165,12 +169,6 @@ class AppDependencies {
myAppointmentsViewModel: getIt(),
),
);
getIt.registerLazySingleton<AppointmentViaRegionViewmodel>(
() => AppointmentViaRegionViewmodel(
navigationService: getIt(),
appState: getIt(),
),
);
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
@ -187,7 +185,21 @@ class AppDependencies {
);
getIt.registerLazySingleton<AppointmentViaRegionViewmodel>(
() => AppointmentViaRegionViewmodel(navigationService: getIt(), appState: getIt()),
() =>
AppointmentViaRegionViewmodel(
navigationService: getIt(),
appState: getIt(),
),
);
getIt.registerLazySingleton<EmergencyServicesViewModel>(
() => EmergencyServicesViewModel(
locationUtils: getIt(),
navServices: getIt(),
emergencyServicesRepo: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
),
);
// Screen-specific VMs Factory

@ -36,21 +36,60 @@ class LocationUtils {
isGMSDevice = GmsCheck().checkGmsAvailability();
}
void getLocation({Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
// final defaultCallbackForLocationDenied = (){
// showCommonBottomSheetWithoutHeight(
// title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
// navigationService.navigatorKey.currentContext!,
// child: Utils.getWarningWidget(
// loadingText:
// "Please grant location permission from app settings to see better results"
// .needTranslation,
// isShowActionButtons: true,
// onCancelTap: () {
// navigationService.pop();
// },
// onConfirmTap: () async {
// navigationService.pop();
// openAppSettings();
// }),
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// }
void getLocation(
{Function(LatLng)? onSuccess,
VoidCallback? onFailure,
bool isShowConfirmDialog = false,
VoidCallback? onLocationDeniedForever}) async {
this.isShowConfirmDialog = isShowConfirmDialog;
if (Platform.isIOS) {
getCurrentLocation(onFailure: onFailure, onSuccess: onSuccess);
getCurrentLocation(
onFailure: onFailure,
onSuccess: onSuccess,
onLocationDeniedForever: onLocationDeniedForever);
return;
}
if (await isGMSDevice ?? true) {
getCurrentLocation(onFailure: onFailure, onSuccess: onSuccess);
getCurrentLocation(
onFailure: onFailure,
onSuccess: onSuccess,
onLocationDeniedForever: onLocationDeniedForever);
return;
}
getHMSLocation(onFailure: onFailure, onSuccess: onSuccess);
getHMSLocation(
onFailure: onFailure,
onSuccess: onSuccess,
onLocationDeniedForever: onLocationDeniedForever);
}
void getCurrentLocation({Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
void getCurrentLocation(
{Function(LatLng)? onSuccess,
VoidCallback? onFailure,
VoidCallback? onLocationDeniedForever}) async {
var location = Location();
bool isLocationEnabled = await location.serviceEnabled();
@ -73,12 +112,15 @@ class LocationUtils {
return;
}
} else if (permissionGranted == LocationPermission.deniedForever) {
if (isShowConfirmDialog) {
appState.resetLocation();
if(onLocationDeniedForever == null && isShowConfirmDialog){
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget(
loadingText: "Please grant location permission from app settings to see the nearest ER location details".needTranslation,
loadingText:
"Please grant location permission from app settings to see better results"
.needTranslation,
isShowActionButtons: true,
onCancelTap: () {
navigationService.pop();
@ -92,6 +134,8 @@ class LocationUtils {
isCloseButtonVisible: true,
);
}
onLocationDeniedForever?.call();
return;
}
Position? currentLocation = await Geolocator.getLastKnownPosition();
@ -209,7 +253,10 @@ class LocationUtils {
appState.userLong = locationData.longitude;
}
void getHMSLocation({VoidCallback? onFailure, Function(LatLng p1)? onSuccess}) async {
void getHMSLocation(
{VoidCallback? onFailure,
Function(LatLng p1)? onSuccess,
VoidCallback? onLocationDeniedForever}) async {
try {
var location = Location();
HmsLocation.FusedLocationProviderClient locationService = HmsLocation.FusedLocationProviderClient()..initFusedLocationService();
@ -230,7 +277,32 @@ class LocationUtils {
LocationPermission permissionGranted = await Geolocator.checkPermission();
if (permissionGranted == LocationPermission.denied) {
permissionGranted = await Geolocator.requestPermission();
if (permissionGranted != LocationPermission.whileInUse && permissionGranted != LocationPermission.always) {
if (permissionGranted == LocationPermission.deniedForever) {
appState.resetLocation();
if(onLocationDeniedForever == null && isShowConfirmDialog){
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget(
loadingText:
"Please grant location permission from app settings to see better results"
.needTranslation,
isShowActionButtons: true,
onCancelTap: () {
navigationService.pop();
},
onConfirmTap: () async {
navigationService.pop();
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
onLocationDeniedForever?.call();
return;
} else if (permissionGranted != LocationPermission.whileInUse && permissionGranted != LocationPermission.always) {
appState.resetLocation();
onFailure?.call();
return;

@ -0,0 +1,19 @@
import 'dart:async';
import 'dart:ui';
class Debouncer {
final int milliseconds;
VoidCallback? action;
Timer? _timer;
Debouncer({required this.milliseconds});
void run(VoidCallback action) {
_timer?.cancel();
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
void dispose() {
_timer?.cancel();
}
}

@ -670,13 +670,17 @@ class Utils {
}
/// Widget to build an SVG from network
static Widget buildImgWithNetwork(
{required String url, required Color iconColor, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover}) {
static Widget buildImgWithNetwork({required String url, required Color iconColor, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover, ImageErrorWidgetBuilder? errorBuilder}) {
return Image.network(
url,
width: width,
height: height,
fit: fit,
errorBuilder: errorBuilder??(_,__,___){
//todo change the error builder icon that it is returning
return Utils.buildSvgWithAssets(width: width,
height: height,icon: AppAssets.no_visit_icon);
},
);
}

@ -734,7 +734,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
onError!(error);
onError?.call(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {

@ -1009,7 +1009,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
onError?.call(apiResponse.errorMessage!);
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
dentalChiefComplaintsList = apiResponse.data!;

@ -0,0 +1,94 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class EmergencyServicesRepo {
Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures();
Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID});
}
class EmergencyServicesRepoImp implements EmergencyServicesRepo {
final ApiClient apiClient;
final LoggerService loggerService;
EmergencyServicesRepoImp({required this.loggerService, required this.apiClient});
Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID}) async {
Map<String, dynamic> mapDevice = {'IsForER': true};
try {
GenericApiModel<List<ProjectAvgERWaitingTime>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_NEAREST_HOSPITAL,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_ProjectAvgERWaitingTime'];
final clinicsList = list.map((item) => ProjectAvgERWaitingTime.fromJson(item as Map<String, dynamic>)).toList().cast<ProjectAvgERWaitingTime>();
apiResponse = GenericApiModel<List<ProjectAvgERWaitingTime>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: clinicsList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<RRTProceduresResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_RRT_PROCEDURE_LIST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['Vida_ProcedureList'];
final proceduresList = list.map((item) => RRTProceduresResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<RRTProceduresResponseModel>();
apiResponse = GenericApiModel<List<RRTProceduresResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: proceduresList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,137 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:url_launcher/url_launcher.dart';
class EmergencyServicesViewModel extends ChangeNotifier {
EmergencyServicesRepo emergencyServicesRepo;
ErrorHandlerService errorHandlerService;
final NavigationService navServices;
final LocationUtils? locationUtils;
final AppState appState;
bool isERListLoading = false;
List<ProjectAvgERWaitingTime> nearestERList = [];
List<ProjectAvgERWaitingTime> nearestERFilteredList = [];
List<RRTProceduresResponseModel> RRTProceduresList = [];
late RRTProceduresResponseModel selectedRRTProcedure;
setSelectedRRTProcedure(RRTProceduresResponseModel procedure) {
selectedRRTProcedure = procedure;
notifyListeners();
}
EmergencyServicesViewModel({
required this.emergencyServicesRepo,
required this.errorHandlerService,
required this.navServices,
required this.locationUtils,
required this.appState,
});
Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async {
RRTProceduresList.clear();
notifyListeners();
final result = await emergencyServicesRepo.getRRTProcedures();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
RRTProceduresList = apiResponse.data!;
selectedRRTProcedure = RRTProceduresList.first;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
void navigateToNearestERPage() {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
navServices.push(
CustomPageRoute(
page: NearestErPage(),
),
);
getNearestER();
});
}
void filterErList(String query) {
print("the query is $query");
if (query.isEmpty) {
nearestERFilteredList = nearestERList;
} else {
nearestERFilteredList = nearestERList.where((er) => er.projectName != null && er.projectName!.toLowerCase().contains(query.toLowerCase())).toList();
}
notifyListeners();
}
// Open directions (navigation) from current location to destination.
Future<void> openDirections({
required double destLat,
required double destLng,
String? travelMode, // driving, walking, bicycling, transit
}) async {
// Try Google Maps app navigation intent (android/iOS)
final modeParam = travelMode == null ? 'driving' : travelMode;
final googleNavUri = Uri.parse('google.navigation:q=$destLat,$destLng&mode=${modeParam.substring(0, 1)}'); // mode: d/w/b/t by scheme
final universalUrl = Uri.parse('https://www.google.com/maps/dir/?api=1&destination=$destLat,$destLng&travelmode=$modeParam');
if (await canLaunchUrl(googleNavUri)) {
await launchUrl(googleNavUri, mode: LaunchMode.externalApplication);
} else {
await launchUrl(universalUrl, mode: LaunchMode.externalApplication);
}
}
Future<void> openDialer(String phoneNumber) async {
final Uri telUri = Uri(scheme: 'tel', path: phoneNumber);
if (await canLaunchUrl(telUri)) {
await launchUrl(telUri, mode: LaunchMode.externalApplication);
} else {
throw 'Could not open dialer for $phoneNumber';
}
}
FutureOr<void> getNearestER() async {
isERListLoading = true;
nearestERList = [];
nearestERFilteredList = [];
notifyListeners();
var response = await emergencyServicesRepo.getNearestEr();
isERListLoading = false;
notifyListeners();
response.fold(
(failure) async {},
(apiResponse) {
isERListLoading = false;
if (apiResponse.messageStatus == 1) {
nearestERList = apiResponse.data!;
nearestERFilteredList = nearestERList;
}
},
);
}
}

@ -0,0 +1,114 @@
class ProjectAvgERWaitingTime {
int? iD;
int? projectID;
int? avgTimeInMinutes;
String? avgTimeInHHMM;
dynamic distanceInKilometers;
String? latitude;
String? longitude;
String? phonenumber;
String? projectImageURL;
String? projectName;
ProjectAvgERWaitingTime(
{this.iD,
this.projectID,
this.avgTimeInMinutes,
this.avgTimeInHHMM,
this.distanceInKilometers,
this.latitude,
this.longitude,
this.phonenumber,
this.projectImageURL,
this.projectName});
ProjectAvgERWaitingTime.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
projectID = json['ProjectID'];
avgTimeInMinutes = json['AvgTimeInMinutes'];
avgTimeInHHMM = json['AvgTimeInHHMM'];
distanceInKilometers = json['DistanceInKilometers'];
latitude = json['Latitude'];
longitude = json['Longitude'];
phonenumber = json['PhoneNumber'];
projectImageURL = json['ProjectImageURL'];
projectName = json['ProjectName'];
}
String getTime(){
print("the name is $projectName");
print("the avgTimeInMinutes is $avgTimeInMinutes");
if(avgTimeInMinutes == null) return "";
int hours = avgTimeInMinutes! ~/ 60;
int minutes = avgTimeInMinutes! % 60;
print("the time is ${"${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}"}");
return "${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}";
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['ProjectID'] = this.projectID;
data['AvgTimeInMinutes'] = this.avgTimeInMinutes;
data['AvgTimeInHHMM'] = this.avgTimeInHHMM;
data['DistanceInKilometers'] = this.distanceInKilometers;
data['Latitude'] = this.latitude;
data['Longitude'] = this.longitude;
data['PhoneNumber'] = this.phonenumber;
data['ProjectImageURL'] = this.projectImageURL;
data['ProjectName'] = this.projectName;
return data;
}
}
//class ProjectAvgERWaitingTime {
// int? iD;
// int? projectID;
// int? avgTimeInMinutes;
// String? avgTimeInHHMM;
// String? distanceInKilometers;
// String? latitude;
// String? longitude;
// String? phonenum?ber;
// String? projectImageURL;
// String? projectName;
//
// ProjectAvgERWaitingTime(
// {this.iD,
// this.projectID,
// this.avgTimeInMinutes,
// this.avgTimeInHHMM,
// this.distanceInKilometers,
// this.latitude,
// this.longitude,
// this.phonenum?ber,
// this.projectImageURL,
// this.projectName});
//
// ProjectAvgERWaitingTime.fromJson(Map<String, dynamic> json) {
// iD = json['ID'];
// projectID = json['ProjectID'];
// avgTimeInMinutes = json['AvgTimeInMinutes'];
// avgTimeInHHMM = json['AvgTimeInHHMM'];
// distanceInKilometers = json['DistanceInKilometers'];
// latitude = json['Latitude'];
// longitude = json['Longitude'];
// phonenum?ber = json['Phonenum?ber'];
// projectImageURL = json['ProjectImageURL'];
// projectName = json['ProjectName'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['ID'] = this.iD;
// data['ProjectID'] = this.projectID;
// data['AvgTimeInMinutes'] = this.avgTimeInMinutes;
// data['AvgTimeInHHMM'] = this.avgTimeInHHMM;
// data['DistanceInKilometers'] = this.distanceInKilometers;
// data['Latitude'] = this.latitude;
// data['Longitude'] = this.longitude;
// data['Phonenum?ber'] = this.phonenum?ber;
// data['ProjectImageURL'] = this.projectImageURL;
// data['ProjectName'] = this.projectName;
// return data;
// }
//}

@ -0,0 +1,27 @@
class RRTProceduresResponseModel {
num? patientShare;
num? patientShareWithTax;
num? patientTaxAmount;
String? procedureID;
String? procedureName;
RRTProceduresResponseModel({this.patientShare, this.patientShareWithTax, this.patientTaxAmount, this.procedureID, this.procedureName});
RRTProceduresResponseModel.fromJson(Map<String, dynamic> json) {
patientShare = json['PatientShare'];
patientShareWithTax = json['PatientShareWithTax'];
patientTaxAmount = json['PatientTaxAmount'];
procedureID = json['ProcedureID'];
procedureName = json['ProcedureName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['PatientShare'] = this.patientShare;
data['PatientShareWithTax'] = this.patientShareWithTax;
data['PatientTaxAmount'] = this.patientTaxAmount;
data['ProcedureID'] = this.procedureID;
data['ProcedureName'] = this.procedureName;
return data;
}
}

@ -110,11 +110,8 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
);
}
}
if (clinicId == 253) {
{
navigationService.push(
CustomPageRoute(
page: LaserAppointment(),

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
@ -125,6 +126,9 @@ void main() async {
),
ChangeNotifierProvider<DoctorFilterViewModel>(
create: (_) => getIt.get<DoctorFilterViewModel>(),
),
ChangeNotifierProvider<EmergencyServicesViewModel>(
create: (_) => getIt.get<EmergencyServicesViewModel>(),
)
], child: MyApp()),
),

@ -43,7 +43,9 @@ class BodyPartsListing extends StatelessWidget {
itemBuilder: (BuildContext context, int index) {
return SizedBox( height: 80, width: 80,).toShimmer2(isShow: isLoading);
})),
GridView.builder(
Visibility(
visible: !isLoading,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 85 / 107,
@ -123,6 +125,7 @@ class BodyPartsListing extends StatelessWidget {
);
},
),
),
],
);
}

@ -303,11 +303,9 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
id = regionalViewModel.selectedHospital?.patientDoctorAppointmentList?.first.projectID?.toString() ?? "";
}
if (bookAppointmentsViewModel.selectedClinic.clinicID == 17) {
if (appState.isAuthenticated) {
initDentalAppointmentBookingFlow(int.parse(bookAppointmentsViewModel
.currentlySelectedHospitalFromRegionFlow ??
"0"));
initDentalAppointment();
return SizedBox.shrink();
}else {
bookAppointmentsViewModel.setIsChiefComplaintsListLoading(true);
}
@ -464,6 +462,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
isCloseButtonVisible: true,
);
} else {
bookAppointmentsViewModel.setIsChiefComplaintsListLoading(true);
Navigator.of(context).push(
CustomPageRoute(
page: DentalChiefComplaintsPage(),
@ -472,4 +471,12 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
}
});
}
void initDentalAppointment() async {
await Future.delayed(Duration(milliseconds: 300));
initDentalAppointmentBookingFlow(int.parse(bookAppointmentsViewModel
.currentlySelectedHospitalFromRegionFlow ??
"0"));
return;
}
}

@ -0,0 +1,46 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/radio/custom_radio_button.dart';
import 'package:provider/provider.dart';
class RrtRequestTypeSelect extends StatelessWidget {
const RrtRequestTypeSelect({super.key});
@override
Widget build(BuildContext context) {
// return Consumer<EmergencyServicesViewModel>(builder: (context, emergencyServicesVM, child) {
return Column(
children: [
Container(
padding: EdgeInsets.all(16.h),
height: 200.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CustomRadioOption(
value: "",
groupValue: "",
onChanged: (value) {},
text: "Home Visit Emergency",
)
],
),
],
),
),
SizedBox(height: 32.h),
],
);
// });
}
}

@ -1,3 +1,4 @@
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/dependencies.dart';
@ -6,23 +7,31 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
class EmergencyServicesPage extends StatelessWidget {
EmergencyServicesPage({super.key});
late EmergencyServicesViewModel emergencyServicesViewModel;
LocationUtils? locationUtils;
@override
Widget build(BuildContext context) {
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
locationUtils = getIt.get<LocationUtils>();
locationUtils!.isShowConfirmDialog = true;
return CollapsingListView(
title: "Emergency Services",
title: "Emergency Services".needTranslation,
requests: () {},
child: Padding(
padding: EdgeInsets.all(24.h),
@ -79,13 +88,7 @@ class EmergencyServicesPage extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
locationUtils!.getLocation(onSuccess: (position) {
Navigator.of(context).push(
CustomPageRoute(
page: NearestErPage(),
),
);
});
context.read<EmergencyServicesViewModel>().navigateToNearestERPage();
}),
),
SizedBox(height: 16.h),
@ -112,7 +115,73 @@ class EmergencyServicesPage extends StatelessWidget {
SizedBox(width: 12.h),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.primaryRedColor,
borderRadius: 24.h,
),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: AppColors.whiteColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulance_alert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
"Confirmation".needTranslation.toText28(color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
"Are you sure you want to call Rapid Response Team (RRT)?".needTranslation.toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
showCommonBottomSheetWithoutHeight(
title: "Rapid Response Team (RRT)".needTranslation,
context,
child: RrtRequestTypeSelect(),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
}),
),
],
),

@ -1,5 +1,21 @@
import 'package:easy_localization/easy_localization.dart' show tr, StringTranslateExtension;
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/nearestERItem.dart' show NearestERItem;
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart' show Selector, WatchContext, ReadContext;
import '../../core/enums.dart' show SelectionTypeEnum;
import '../../core/utils/debouncer.dart' show Debouncer;
class NearestErPage extends StatefulWidget {
const NearestErPage({super.key});
@ -9,11 +25,80 @@ class NearestErPage extends StatefulWidget {
}
class _NearestErPageState extends State<NearestErPage> {
final TextEditingController searchText = TextEditingController();
final Debouncer debouncer = Debouncer(milliseconds: 500);
@override
void dispose() {
debouncer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CollapsingListView(
title: "Nearest ER",
child: Container(),
title: "Nearest ER".needTranslation,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: 'Type any facility name'.needTranslation,
controller: searchText,
onChange: (value) {
debouncer.run(() {
context.read<EmergencyServicesViewModel>().filterErList(value ?? '');
});
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
isAllowLeadingIcon: true,
leadingIcon: AppAssets.search_icon,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
),
Selector<EmergencyServicesViewModel, bool>(
selector: (___, viewModel) => viewModel.isERListLoading,
builder: (_, isLoading, __) => Selector<EmergencyServicesViewModel, List<ProjectAvgERWaitingTime>>(
selector: (___, viewModel) => viewModel.nearestERFilteredList,
shouldRebuild: (previous, next) => previous != next,
builder: (_, value, __) {
if (isLoading || value.isNotEmpty) {
return ListView.separated(
padding: EdgeInsets.only(top: 24.h),
itemCount: isLoading ? 6 : value.length,
separatorBuilder: (____, _____) => SizedBox(
height: 16.h,
),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: NearestERItem(
isLoading: isLoading,
nearestERItem: isLoading ? ProjectAvgERWaitingTime() : value[index],
))));
},
);
} else {
return Center(child: Utils.getNoDataWidget(context, noDataText: "No nearest Er Arround you".needTranslation));
}
}),
),
],
).paddingAll(16.h),
));
}
}

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:provider/provider.dart';
class NearestERItem extends StatelessWidget {
final ProjectAvgERWaitingTime nearestERItem;
final bool isLoading;
const NearestERItem({ super.key,
required this.nearestERItem,
required this.isLoading
}) ;
@override
Widget build(BuildContext context) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
customBorder: BorderRadius.only(
topLeft: Radius.circular(24.h),
topRight: Radius.circular(24.h),
),
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
(isLoading || nearestERItem.projectImageURL?.isEmpty == true)
? Container(
width: 24.h,
height: 24.h,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
).toShimmer2(isShow: isLoading)
: Utils.buildImgWithNetwork(
url: nearestERItem.projectImageURL ?? '',
iconColor: Colors.transparent,
).circle(24.h).toShimmer2(isShow: isLoading),
const SizedBox(width: 12),
Expanded(
child: (nearestERItem.projectName?.toText16(
color: AppColors.textColor,
weight: FontWeight.w600,
) ??
SizedBox.shrink()).toShimmer2(isShow: isLoading),
),
// TODO: Add hospital icon logic here if needed
],
),
SizedBox(height: 8.h),
Row(
spacing: 8.h,
children: [
AppCustomChipWidget(
labelText: "${nearestERItem.distanceInKilometers} km".needTranslation,
icon: AppAssets.location,
iconHasColor: false,
labelPadding: EdgeInsetsDirectional.only(start: 4.h, end: 0.h),
padding: EdgeInsets.all(8.h),
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "Expected waiting time: ${nearestERItem.getTime()} mins".needTranslation,
icon: AppAssets.waiting_time_clock,
iconHasColor: false,
labelPadding: EdgeInsetsDirectional.only(start: 4.h, end: 0.h),
padding: EdgeInsets.all(8.h),
).toShimmer2(isShow: isLoading),
],
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: CustomButton(
text: "View Location on Google Maps".needTranslation,
iconSize: 18.h,
icon: AppAssets.location,
onPressed: () {
context.read<EmergencyServicesViewModel>().openDirections(destLat: double.parse(nearestERItem.latitude??"0.0"), destLng: double.parse(nearestERItem.longitude??"0.0") );
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
iconColor: AppColors.primaryRedColor,
height: 40.h,
fontSize: 14,
fontWeight: FontWeight.w500,
).toShimmer2(isShow: isLoading),
),
SizedBox(width: 8.h),
SizedBox(
height: 40.h,
width: 40.h,
child: CustomButton(
text: '',
iconSize: 18.h,
icon: AppAssets.call_fill,
onPressed: () {
context.read<EmergencyServicesViewModel>().openDialer( nearestERItem.phonenumber??"");
},
backgroundColor: AppColors.greyColor,
iconColor: AppColors.textColor,
borderColor: AppColors.greyColor,
height: 40.h,
).toShimmer2(isShow: isLoading),
),
],
),
],
),
),
);
}
}

@ -64,15 +64,14 @@ class DialogServiceImp implements DialogService {
onOkPressed: () {
if (onOkPressed != null) {
onOkPressed();
} else {
context.pop();
}
context.pop();
},
onCancelPressed: () {
if (onCancelPressed != null) {
context.pop();
onCancelPressed();
}
context.pop();
},
),
);

@ -70,22 +70,26 @@ class CustomButton extends StatelessWidget {
children: [
if (icon != null)
Padding(
padding: EdgeInsets.only(right: 8.h, left: 8.h),
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS),
padding: text.isNotEmpty ?EdgeInsets.only(right: 8.h, left: 8.h): EdgeInsets.zero,
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconSize, height: iconSize),
),
Padding(
Visibility(
visible: text.isNotEmpty,
child: Padding(
padding: EdgeInsets.only(top: 0),
child: Text(
text,
overflow: textOverflow,
style: context.dynamicTextStyle(
fontSize: fontS,
fontSize: fontSize.fSize,
color: isDisabled ? textColor.withOpacity(0.5) : textColor,
letterSpacing: 0,
fontWeight: fontWeight,
),
),
),
),
],
),
));

@ -114,6 +114,8 @@ void showCommonBottomSheetWithoutHeight(
bool isDismissible = true,
Widget? titleWidget,
bool useSafeArea = false,
bool hasBottomPadding = true,
Color backgroundColor = AppColors.bottomSheetBgColor,
}) {
showModalBottomSheet<String>(
sheetAnimationStyle: AnimationStyle(
@ -127,13 +129,14 @@ void showCommonBottomSheetWithoutHeight(
isScrollControlled: true,
showDragHandle: false,
isDismissible: isDismissible,
backgroundColor: AppColors.bottomSheetBgColor,
backgroundColor: backgroundColor,
useSafeArea: useSafeArea,
builder: (BuildContext context) {
return SafeArea(
top: false,
left: false,
right: false,
bottom: hasBottomPadding,
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
@ -164,8 +167,8 @@ void showCommonBottomSheetWithoutHeight(
child: title.toText20(weight: FontWeight.w600),
),
Utils.buildSvgWithAssets(
icon: AppAssets.cross_circle,
height: 24.h,
icon: AppAssets.close_bottom_sheet_icon,
iconColor: Color(0xff2B353E),
).onPress(() {
Navigator.of(context).pop();
}),

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class CustomRadioOption<T> extends StatelessWidget {
final T value;
final T? groupValue;
final ValueChanged<T?> onChanged;
final String text;
// final Widget child; // The content of your radio option (e.g., Text, Image)
const CustomRadioOption({
super.key,
required this.value,
required this.groupValue,
required this.onChanged,
// required this.child,
required this.text,
});
@override
Widget build(BuildContext context) {
// bool isSelected = value == groupValue;
bool isSelected = false;
return InkWell(
onTap: () => onChanged(value),
child: Container(
padding: EdgeInsets.all(8.h),
child: Row(
children: [
Container(
width: 20.h,
height: 20.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor,
border: Border.all(color: isSelected ? AppColors.primaryRedColor : AppColors.bottomNAVBorder, width: 2.h),
),
),
SizedBox(width: 8.h),
text.toText16(weight: FontWeight.w500), // The provided content
],
),
),
);
}
}
Loading…
Cancel
Save