Merge branch 'master' into dev_aamir

# Conflicts:
#	lib/core/api_consts.dart
#	lib/features/authentication/authentication_view_model.dart
pull/27/head
aamir-csol 2 months ago
commit 6f011880bd

@ -0,0 +1,4 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.7494 6.84523C15.6598 4.59011 13.7806 2.69067 11.2973 2.75142C10.7204 2.76553 10.0421 2.95699 8.97809 3.25735L8.84753 3.2942C5.92379 4.11888 3.05604 5.59448 2.37359 9.07412C2.24987 9.70491 2.24992 10.4012 2.25 11.5693L2.25 13.4307C2.24992 14.5988 2.24987 15.2951 2.37359 15.9259C3.05604 19.4055 5.92379 20.8811 8.84752 21.7058L8.97806 21.7427C10.0421 22.043 10.7204 22.2345 11.2973 22.2486C13.7806 22.3093 15.6598 20.4099 15.7494 18.1548C15.7659 17.7409 15.4437 17.392 15.0298 17.3756C14.6159 17.3591 14.267 17.6813 14.2506 18.0952C14.193 19.544 12.9856 20.7894 11.334 20.749C10.9722 20.7402 10.493 20.6114 9.25473 20.2621C6.45545 19.4726 4.35508 18.2352 3.84554 15.6372C3.75341 15.1675 3.75001 14.6267 3.75001 13.3373L3.75001 11.6628C3.75001 10.3733 3.75341 9.83255 3.84554 9.36281C4.35508 6.76484 6.45545 5.52745 9.25474 4.73787C10.493 4.38859 10.9722 4.25982 11.334 4.25097C12.9856 4.21057 14.193 5.45605 14.2506 6.9048C14.267 7.31868 14.6159 7.64087 15.0298 7.62442C15.4437 7.60797 15.7659 7.25912 15.7494 6.84523Z" fill="#ED1C2B"/>
<path d="M19.0227 9.46219C18.7257 9.17349 18.2509 9.18023 17.9622 9.47726C17.6735 9.77428 17.6802 10.2491 17.9773 10.5378C18.1388 10.6949 18.396 10.8971 18.6407 11.0893L18.6976 11.134C18.9434 11.327 19.2061 11.5333 19.4548 11.7439L19.4619 11.75L10 11.75C9.58579 11.75 9.25 12.0858 9.25 12.5C9.25 12.9142 9.58579 13.25 10 13.25L19.4619 13.25L19.4548 13.2561C19.2061 13.4668 18.9434 13.673 18.6976 13.866L18.6407 13.9107C18.396 14.1029 18.1388 14.3051 17.9773 14.4622C17.6802 14.7509 17.6735 15.2257 17.9622 15.5227C18.2509 15.8198 18.7257 15.8265 19.0227 15.5378C19.114 15.4491 19.2958 15.3035 19.5672 15.0903L19.6272 15.0432C19.8693 14.8532 20.1534 14.6302 20.4245 14.4005C20.715 14.1543 21.0168 13.8787 21.2515 13.6032C21.369 13.4652 21.485 13.3096 21.5746 13.1422C21.661 12.9807 21.75 12.7583 21.75 12.5C21.75 12.2417 21.661 12.0193 21.5746 11.8578C21.485 11.6904 21.369 11.5348 21.2515 11.3968C21.0168 11.1213 20.715 10.8457 20.4245 10.5995C20.1534 10.3698 19.8693 10.1469 19.6272 9.95679L19.5672 9.90971C19.2958 9.69651 19.114 9.55089 19.0227 9.46219Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -726,7 +726,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -802,9 +802,9 @@ class ApiConsts {
static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI';
static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo';
static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege';
static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration';
static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo';
static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege';
static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration';
// static values for Api
static final double appVersionID = 18.7;

@ -93,6 +93,7 @@ class AppAssets {
static const String checkin_location_icon = '$svgBasePath/checkin_location_icon.svg';
static const String checkin_nfc_icon = '$svgBasePath/checkin_nfc_icon.svg';
static const String checkin_qr_icon = '$svgBasePath/checkin_qr_icon.svg';
static const String logout = '$svgBasePath/logout.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';

@ -39,13 +39,15 @@ extension WidgetExtensions on Widget {
child: this,
);
Widget toShimmer2({bool isShow = true, double radius = 20}) => isShow
Widget toShimmer2({bool isShow = true, double radius = 20, double? width, double? height}) => isShow
? Shimmer.fromColors(
baseColor: const Color(0xffe8eff0),
highlightColor: Colors.white,
child: ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: Container(
width: width,
height: height,
color: Colors.white,
child: this,
),

@ -37,6 +37,8 @@ abstract class AuthenticationRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientIMEIData({required dynamic patientIMEIDataRequest});
Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientDeviceData({required dynamic patientDeviceDataRequest});
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientDeviceData({required dynamic patientDeviceDataRequest});
}
class AuthenticationRepoImp implements AuthenticationRepo {
@ -490,4 +492,39 @@ class AuthenticationRepoImp implements AuthenticationRepo {
return Future.value(Left(UnknownFailure(e.toString())));
}
}
@override
Future<Either<Failure, GenericApiModel>> getPatientDeviceData({required patientDeviceDataRequest}) {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
return apiClient.post(
ApiConsts.getPatientMobileData,
body: patientDeviceDataRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
).then( (_) {
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
});
} catch (e) {
return Future.value(Left(UnknownFailure(e.toString())));
}
}
}

@ -31,8 +31,10 @@ import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/localauth_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/bottomsheet/exception_bottom_sheet.dart';
import 'models/request_models/get_user_mobile_device_data.dart';
import 'models/request_models/insert_patient_mobile_deviceinfo.dart';
import 'models/request_models/patient_insert_device_imei_request.dart';
@ -80,10 +82,11 @@ class AuthenticationViewModel extends ChangeNotifier {
String errorMsg = '';
final FocusNode myFocusNode = FocusNode();
var healthId;
int getDeviceLastLogin =1;
Future<void> onLoginPressed() async {
try {
LoadingUtils.showFullScreenLoader();
LoaderBottomSheet.showLoader();
//TODO: We will remove this delay
// await Future.delayed(Duration(seconds: 3));
var data = _appState.getSelectDeviceByImeiRespModelElement;
@ -95,7 +98,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
} catch (e) {
log("Error in onLoginPressed: $e");
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
_dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {});
}
}
@ -192,7 +195,7 @@ class AuthenticationViewModel extends ChangeNotifier {
(failure) async {
// LoadingUtils.hideFullScreenLoader();
// await _errorHandlerService.handleError(failure: failure);
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen());
},
(apiResponse) {
@ -211,7 +214,7 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> _handleExistingImeiData(dynamic data) async {
try {
SelectDeviceByImeiRespModelElement? savedData = _appState.getSelectDeviceByImeiRespModelElement;
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
if (savedData != null) {
// TODO: Navigate to SavedLogin when available
@ -220,7 +223,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
} catch (e) {
log("Error handling existing IMEI data: $e");
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen());
}
}
@ -231,7 +234,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (respData != null) {
dynamic data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
_appState.setSelectDeviceByImeiRespModelElement(data);
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
// TODO: Navigate to SavedLogin when available
// SelectDeviceByImeiRespModelElement savedData =
@ -239,16 +242,17 @@ class AuthenticationViewModel extends ChangeNotifier {
_navigationService.pushPage(page: SavedLogin());
// _navigationService.pushPage(page: LoginScreen());
} else {
LoadingUtils.hideFullScreenLoader();
print("print login........");
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen());
}
} catch (e) {
log("Error processing IMEI registration response: $e");
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen());
}
}, onError: (String error) {
LoadingUtils.hideFullScreenLoader();
LoaderBottomSheet.hideLoader();
_dialogService.showErrorBottomSheet(message: error, onOkPressed: () {});
});
}
@ -269,8 +273,8 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!isValidated) {
return;
}
LoadingUtils.showFullScreenLoader();
LoaderBottomSheet.showLoader();
// LoadingUtils.showFullScreenLoader();
dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest(
phoneNumber: phoneNumberController.text,
@ -283,20 +287,22 @@ class AuthenticationViewModel extends ChangeNotifier {
calenderType: calenderType);
final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
LoadingUtils.hideFullScreenLoader();
result.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['isSMSSent']) {
_appState.setAppAuthToken = apiResponse.data['LogInTokenID'];
sendActivationCode(
await sendActivationCode(
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
);
} else {
if (apiResponse.data['IsAuthenticated']) {
await checkActivationCode(
@ -304,6 +310,7 @@ class AuthenticationViewModel extends ChangeNotifier {
onWrongActivationCode: (String? message) {},
activationCode: null, //todo silent login case halded on the repo itself..
);
}
}
}
@ -338,9 +345,11 @@ class AuthenticationViewModel extends ChangeNotifier {
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty");
} else {
if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) {
LoaderBottomSheet.hideLoader();
navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
} else {
// TODO: Handle isSMSSent false
@ -375,8 +384,8 @@ class AuthenticationViewModel extends ChangeNotifier {
countryCode: selectedCountrySignup.countryCode,
loginType: loginTypeEnum.toInt)
.toJson();
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == 1) ? true : false;
LoaderBottomSheet.showLoader();
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true);
if (isForRegister) {
if (_appState.getUserRegistrationPayload.patientOutSa == 0) request['DOB'] = _appState.getUserRegistrationPayload.dob;
request['HealthId'] = _appState.getUserRegistrationPayload.healthId;
@ -394,6 +403,8 @@ class AuthenticationViewModel extends ChangeNotifier {
final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: request, activationCode: activationCode.toString(), isRegister: true);
LoaderBottomSheet.hideLoader();
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (_appState.getUserRegistrationPayload.isRegister == true) {
@ -413,19 +424,26 @@ class AuthenticationViewModel extends ChangeNotifier {
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (activation.errorCode == '699') {
// Todo: Hide Loader
// GifLoaderDialogUtils.hideDialog(context);
LoaderBottomSheet.hideLoader();
onWrongActivationCode(activation.errorEndUserMessage);
return;
} else if (activation.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
onWrongActivationCode(activation.errorEndUserMessage);
return;
} else if (_appState.getUserRegistrationPayload.isRegister == true) {
LoaderBottomSheet.hideLoader();
_navigationService.pushAndReplace(AppRoutes.registerStepTwo);
// Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
return;
} else {
if (activation.list != null && activation.list!.isNotEmpty) {
_appState.setAuthenticatedUser(activation.list!.first);
}
@ -433,6 +451,12 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setAppAuthToken = activation.authenticationTokenId;
final request = RequestUtils.getAuthanticatedCommonRequest().toJson();
bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request);
//updating the last login type in app state to show the fingerprint/face id option on home screen
if( _appState.getSelectDeviceByImeiRespModelElement !=null) {
_appState.getSelectDeviceByImeiRespModelElement!.logInType = loginTypeEnum.toInt;
}
LoaderBottomSheet.hideLoader();
insertPatientIMEIData(loginTypeEnum.toInt);
clearDefaultInputValues();
if (isUserAgreedBefore) {
@ -519,20 +543,22 @@ class AuthenticationViewModel extends ChangeNotifier {
await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {});
}
loginWithFingerPrintFace() async {
loginWithFingerPrintFace(Function success) async {
_localAuthService.authenticate().then((value) async {
if (value) {
// we have to handle this if verification true;
LoaderBottomSheet.showLoader();
success();
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
if (!_appState.isAuthenticated) {
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
print(loginTypeEnum);
checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
insertPatientIMEIData((_appState.deviceTypeID == 1 ? LoginTypeEnum.face.toInt : LoginTypeEnum.fingerprint.toInt));
//commenting this api to check either the same flow working or not because this api does not needed further if work fine we will remove this
// await getPatientDeviceData(loginTypeEnum.toInt);
await checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
await insertPatientIMEIData(loginTypeEnum.toInt);
} else {
// authenticated = true;
insertPatientIMEIData((_appState.deviceTypeID == 1 ? LoginTypeEnum.face.toInt : LoginTypeEnum.fingerprint.toInt));
await insertPatientIMEIData(loginTypeEnum.toInt);
}
LoaderBottomSheet.hideLoader();
notifyListeners();
// navigateToHomeScreen();
} else {
@ -740,6 +766,7 @@ class AuthenticationViewModel extends ChangeNotifier {
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!,
patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
firstName: _appState.getAuthenticatedUser()!.firstName!,
lastName: _appState.getAuthenticatedUser()!.lastName!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType,
@ -786,6 +813,33 @@ class AuthenticationViewModel extends ChangeNotifier {
log("Insert IMEI Failed");
}
});
}
Future<void> getPatientDeviceData(int loginType) async {
final resultEither = await _authenticationRepo.getPatientDeviceData(
patientDeviceDataRequest: GetUserMobileDeviceData(
deviceToken: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!,
patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType,
patientOutSa:_appState.getSelectDeviceByImeiRespModelElement!.outSa == true ?1 :0,
loginType: loginType,
languageId: _appState.getLanguageID(),
latitude: _appState.userLat,
longitude: _appState.userLong,
mobileNo:_appState.getSelectDeviceByImeiRespModelElement!.mobile! ,
patientMobileNumber:int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!),
nationalId:_appState.getSelectDeviceByImeiRespModelElement!.identificationNo)
.toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) {
dynamic deviceInfo= apiResponse.data['List_MobileLoginInfo'];
getDeviceLastLogin = deviceInfo['LoginType'];
}
});
}
@override

@ -0,0 +1,113 @@
import 'dart:convert';
class GetUserMobileDeviceData {
int? patientMobileNumber;
String? mobileNo;
String? deviceToken;
bool? projectOutSa;
int? loginType;
String? zipCode;
bool? isRegister;
String? logInTokenId;
int? searchType;
int? patientId;
String? nationalId;
String? patientIdentificationId;
int? otpSendType;
int? languageId;
double? versionId;
int? channel;
String? ipAdress;
String? generalid;
int? patientOutSa;
bool? isDentalAllowedBackend;
int? deviceTypeId;
double? latitude;
double? longitude;
int? patientType;
GetUserMobileDeviceData({
this.patientMobileNumber,
this.mobileNo,
this.deviceToken,
this.projectOutSa,
this.loginType,
this.zipCode,
this.isRegister,
this.logInTokenId,
this.searchType,
this.patientId,
this.nationalId,
this.patientIdentificationId,
this.otpSendType,
this.languageId,
this.versionId,
this.channel,
this.ipAdress,
this.generalid,
this.patientOutSa,
this.isDentalAllowedBackend,
this.deviceTypeId,
this.latitude,
this.longitude,
this.patientType,
});
factory GetUserMobileDeviceData.fromRawJson(String str) => GetUserMobileDeviceData.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetUserMobileDeviceData.fromJson(Map<String, dynamic> json) => GetUserMobileDeviceData(
patientMobileNumber: json["PatientMobileNumber"],
mobileNo: json["MobileNo"],
deviceToken: json["DeviceToken"],
projectOutSa: json["ProjectOutSA"],
loginType: json["LoginType"],
zipCode: json["ZipCode"],
isRegister: json["isRegister"],
logInTokenId: json["LogInTokenID"],
searchType: json["SearchType"],
patientId: json["PatientID"],
nationalId: json["NationalID"],
patientIdentificationId: json["PatientIdentificationID"],
otpSendType: json["OTP_SendType"],
languageId: json["LanguageID"],
versionId: json["VersionID"]?.toDouble(),
channel: json["Channel"],
ipAdress: json["IPAdress"],
generalid: json["generalid"],
patientOutSa: json["PatientOutSA"],
isDentalAllowedBackend: json["isDentalAllowedBackend"],
deviceTypeId: json["DeviceTypeID"],
latitude: json["Latitude"],
longitude: json["Longitude"],
patientType: json["PatientType"],
);
Map<String, dynamic> toJson() => {
"PatientMobileNumber": patientMobileNumber,
"MobileNo": mobileNo,
"DeviceToken": deviceToken,
"ProjectOutSA": projectOutSa,
"LoginType": loginType,
"ZipCode": zipCode,
"isRegister": isRegister,
"LogInTokenID": logInTokenId,
"SearchType": searchType,
"PatientID": patientId,
"NationalID": nationalId,
"PatientIdentificationID": patientIdentificationId,
"OTP_SendType": otpSendType,
"LanguageID": languageId,
"VersionID": versionId,
"Channel": channel,
"IPAdress": ipAdress,
"generalid": generalid,
"PatientOutSA": patientOutSa,
"isDentalAllowedBackend": isDentalAllowedBackend,
"DeviceTypeID": deviceTypeId,
"Latitude": latitude,
"Longitude": longitude,
"PatientType": patientType,
};
}

@ -2,9 +2,11 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -22,6 +24,7 @@ class _QuickLogin extends State<QuickLogin> {
@override
Widget build(BuildContext context) {
NavigationService navigationService = getIt.get<NavigationService>();
return Container(
decoration: const BoxDecoration(
color: Colors.white,
@ -43,7 +46,7 @@ class _QuickLogin extends State<QuickLogin> {
children: [
InkWell(
onTap: () {
Navigator.pop(context, true);
navigationService.pop();
},
child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle)),
],
@ -101,9 +104,6 @@ class _QuickLogin extends State<QuickLogin> {
text:LocaleKeys.enableQuickLogin.tr(),
onPressed: () {
widget.onPressed();
setState(() {
});
},
backgroundColor: Color(0xffED1C2B),
borderColor: Color(0xffED1C2B),

@ -42,7 +42,7 @@ class _SavedLogin extends State<SavedLogin> {
authVm.nationalIdController.text = appState.getSelectDeviceByImeiRespModelElement!.identificationNo!;
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace();
authVm.loginWithFingerPrintFace((){});
}
super.initState();
@ -101,7 +101,7 @@ class _SavedLogin extends State<SavedLogin> {
text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace();
authVm.loginWithFingerPrintFace((){});
} else {
// int? val = loginType.toInt;
authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp);
@ -114,7 +114,8 @@ class _SavedLogin extends State<SavedLogin> {
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
icon: AppAssets.sms,
icon: getTypeIcons(loginType.toInt), //loginType == LoginTypeEnum.sms ? AppAssets.sms :AppAssets.whatsapp,
iconColor: loginType != LoginTypeEnum.whatsapp ? Colors.white: null ,
),
),
],
@ -210,7 +211,8 @@ class _SavedLogin extends State<SavedLogin> {
textColor: AppColors.textColor,
borderWidth: 2,
padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
icon: AppAssets.password_validation,
icon: AppAssets.sms,
iconColor: AppColors.textColor,
)
: Container(),
SizedBox(
@ -224,7 +226,7 @@ class _SavedLogin extends State<SavedLogin> {
iconColor: null,
onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace();
authVm.loginWithFingerPrintFace((){});
} else {
loginType = LoginTypeEnum.whatsapp;
int? val = loginType.toInt;

@ -23,6 +23,7 @@ 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/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart' show CustomTabBar;
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
@ -35,14 +36,14 @@ class LandingPage extends StatefulWidget {
class _LandingPageState extends State<LandingPage> {
late final AuthenticationViewModel authVM;
bool isDone = false;
@override
void initState() {
authVM = context.read<AuthenticationViewModel>();
authVM.savePushTokenToAppState();
if (mounted) {
authVM.checkLastLoginStatus(() {
showQuickLogin(context, false);
showQuickLogin(context);
});
}
super.initState();
@ -321,20 +322,33 @@ class _LandingPageState extends State<LandingPage> {
);
}
void showQuickLogin(BuildContext context, bool isDone) {
showCommonBottomSheet(
void showQuickLogin(BuildContext context) {
showCommonBottomSheetWithoutHeight(
context,
title: "",
child: QuickLogin(
isCloseButtonVisible: false,
child:
StatefulBuilder(
builder: (context, setState) {
return QuickLogin(
isDone: isDone,
onPressed: () {
// sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true);
authVM.loginWithFingerPrintFace();
authVM.loginWithFingerPrintFace((){
isDone = true;
setState(() {
});
});
},
),
height: isDone == false ? ResponsiveExtension.screenHeight * 0.5 : ResponsiveExtension.screenHeight * 0.3,
);
}),
// height: isDone == false ? ResponsiveExtension.screenHeight * 0.5 : ResponsiveExtension.screenHeight * 0.3,
isFullScreen: false,
callBackFunc: (str) {
callBackFunc: () {
isDone = true;
setState(() {});
},

@ -0,0 +1,149 @@
import 'dart:ui';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
class CollapsingListView extends StatelessWidget {
final String title;
Widget? child;
VoidCallback? search;
VoidCallback? report;
VoidCallback? logout;
VoidCallback? history;
Widget? bottomChild;
bool isClose;
CollapsingListView({required this.title, this.child, this.search, this.isClose = false, this.bottomChild, this.report, this.logout, this.history});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: 100,
stretch: true,
systemOverlayStyle: SystemUiOverlayStyle(statusBarBrightness: Brightness.light),
surfaceTintColor: Colors.transparent,
backgroundColor: AppColors.bgScaffoldColor,
leading: IconButton(
icon: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 32.h, height: 32.h),
padding: EdgeInsets.only(left: 12),
onPressed: () => Navigator.pop(context),
),
flexibleSpace: LayoutBuilder(
builder: (context, constraints) {
final double maxHeight = 100;
final double minHeight = kToolbarHeight;
double t = (constraints.maxHeight - minHeight) / (maxHeight - minHeight);
t = t - 1;
if (t < 0.7) t = 0.7;
t = t.clamp(0.0, 1.0);
final double fontSize = lerpDouble(14, 18, t)!;
final double bottomPadding = lerpDouble(0, 0, t)!;
final double leftPadding = lerpDouble(150, 24, t)!;
return Stack(
children: [
Align(
alignment: Alignment.lerp(
Alignment.center,
Alignment.bottomLeft,
t,
)!,
child: Padding(
padding: EdgeInsets.only(left: leftPadding, bottom: bottomPadding),
child: Row(
spacing: 4.h,
children: [
Text(
title,
maxLines: 1,
style: TextStyle(
fontSize: (27 - (5 * (2 - t))).fSize,
fontWeight: FontWeight.lerp(
FontWeight.w300,
FontWeight.w600,
t,
)!,
color: AppColors.blackColor,
letterSpacing: -0.5),
).expanded,
if (logout != null) actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!),
if (report != null) actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(report!),
if (history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(history!),
if (search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(search!).paddingOnly(right: 24)
],
)),
),
],
);
},
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => child,
childCount: 1,
),
),
],
).expanded,
if (bottomChild != null) bottomChild!
],
),
);
}
Widget actionButton(BuildContext context, double t, {required String title, required String icon}) {
return AnimatedSize(
duration: Duration(milliseconds: 150),
child: Container(
height: 40,
padding: EdgeInsets.all(8),
margin: EdgeInsets.only(right: 24),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.secondaryLightRedColor,
borderRadius: 12,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
spacing: 8.h,
children: [
Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.primaryRedColor),
if (t == 1)
Text(
title,
style: context.dynamicTextStyle(
color: AppColors.primaryRedColor,
letterSpacing: -0.4,
fontSize: (14 - (2 * (1 - t))).fSize,
fontWeight: FontWeight.lerp(
FontWeight.w300,
FontWeight.w500,
t,
)!,
),
),
],
),
),
);
}
}

@ -1,26 +1,21 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
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/enums.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.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/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.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/custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget {
const LabOrdersPage({super.key});
@ -32,7 +27,8 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
late LabViewModel labProvider;
List<List<TestDetails>?> labSuggestions = [];
int? expandedIndex;
String? selectedFilterText='';
String? selectedFilterText = '';
@override
void initState() {
scheduleMicrotask(() {
@ -45,214 +41,75 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
Widget build(BuildContext context) {
labProvider = Provider.of<LabViewModel>(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.labResults.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Padding(
padding: EdgeInsets.all(24.h),
child: SingleChildScrollView(
child: Consumer<LabViewModel>(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.labResults.tr(context: context).toText24(isBold: true),
Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(() {
if (model.isLabOrdersLoading) {
return;
}else {
showCommonBottomSheet(context, child: SearchLabResultsContent(labSuggestionsList: model.labSuggestions),
callBackFunc: (value) {
selectedFilterText = value;
model.filterLabReports(value!);
},
title: LocaleKeys.searchLabReport.tr(),
height: ResponsiveExtension.screenHeight,
isFullScreen: true,
isCloseButtonVisible: true);
}
}),
],
),
SizedBox(height: 16.h),
// Build Tab Bar
SizedBox(height: 16.h),
// Expandable list
selectedFilterText!.isNotEmpty ? CustomChipWidget(chipText: selectedFilterText!, chipType: ChipTypeEnum.alert, isSelected: true, ) : SizedBox(),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? const MoviesShimmerWidget()
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: getLabOrderStatusText(model.patientLabOrders[index].status!),
onPressed: () {},
backgroundColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.15),
borderColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.01),
textColor: getLabOrderStatusColor(model.patientLabOrders[index].status!),
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
Row(
children: [
Image.network(
model.patientLabOrders[index].doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 4.h),
model.patientLabOrders[index].doctorName!.toText16(isBold: true)
],
),
SizedBox(height: 8.h),
Row(
children: [
CustomButton(
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientLabOrders[index].createdOn), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
SizedBox(width: 8.h),
CustomButton(
text: model.patientLabOrders[index].clinicDescription!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
],
),
],
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
switchInCurve: Curves.easeIn,
switchOutCurve: Curves.easeOut,
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: 0.0,
child: child,
),
);
},
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...model.patientLabOrders[index].testDetails!.map((detail) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${detail.description}'.toText14(weight: FontWeight.w500),
);
}).toList(),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
)
: SizedBox.shrink(key: ValueKey<int>(-index)),
),
],
),
),
),
body: CollapsingListView(
title: LocaleKeys.labResults.tr(),
search: () async {
final lavVM = Provider.of<LabViewModel>(context, listen: false);
if (lavVM.isLabOrdersLoading) {
return;
} else {
String? value = await Navigator.of(context).push(CupertinoPageRoute(fullscreenDialog: true, builder: (context) => SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions)));
if (value != null) {
selectedFilterText = value;
lavVM.filterLabReports(value);
}
}
},
child: SingleChildScrollView(
padding: EdgeInsets.all(24),
physics: NeverScrollableScrollPhysics(),
child: Consumer<LabViewModel>(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
selectedFilterText!.isNotEmpty
? CustomChipWidget(
chipText: selectedFilterText!,
chipType: ChipTypeEnum.alert,
isSelected: true,
)
: SizedBox(),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded)),
),
),
);
},
),
],
);
},
);
},
),
],
);
},
),
),
),
),
);
));
}
Color getLabOrderStatusColor(num status) {

@ -0,0 +1,172 @@
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_export.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.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/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.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';
class LabResultItemView extends StatelessWidget {
final VoidCallback onTap;
final int index;
final PatientLabOrdersResponseModel? labOrder;
final bool isLoading;
final bool isExpanded;
LabResultItemView({Key? key, required this.onTap, this.labOrder, required this.index, this.isLoading = false, this.isExpanded = false}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
if (!isLoading) {
onTap();
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
labelText: getLabOrderStatusText(labOrder?.status ?? 0, context),
backgroundColor: getLabOrderStatusColor(labOrder?.status ?? 0).withOpacity(0.15),
textColor: getLabOrderStatusColor(labOrder?.status ?? 0),
).toShimmer2(isShow: isLoading, width: 100),
if (!isLoading) Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
Row(
children: [
Image.network(
isLoading ? "" : labOrder!.doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
errorBuilder: (cxt, child, tr) {
return SizedBox(height: 24, width: 24);
},
).toShimmer2(isShow: isLoading).circle(100),
SizedBox(width: 4.h),
(labOrder?.doctorName ?? "").toText16(isBold: true).toShimmer2(isShow: isLoading, width: 200)
],
),
SizedBox(height: 8.h),
Wrap(
spacing: 8.h,
runSpacing: 0.h,
children: [
AppCustomChipWidget(labelText: isLoading ? "null" : DateUtil.formatDateToDate(DateUtil.convertStringToDate(labOrder!.createdOn), false)).toShimmer2(isShow: isLoading, width: 70),
AppCustomChipWidget(labelText: isLoading ? "null" : labOrder!.clinicDescription!).toShimmer2(isShow: isLoading, width: 100),
],
),
],
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
switchInCurve: Curves.easeIn,
switchOutCurve: Curves.easeOut,
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: 0.0,
child: child,
),
);
},
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...labOrder!.testDetails!.map((detail) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${detail.description}'.toText14(weight: FontWeight.w500),
);
}).toList(),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
)
: SizedBox.shrink(key: ValueKey<int>(-index)),
),
],
),
),
);
}
String getLabOrderStatusText(num status, context) {
switch (status) {
case 44:
return LocaleKeys.resultsPending.tr(context: context);
case 45:
return LocaleKeys.resultsPending.tr(context: context);
case 16:
return LocaleKeys.resultsAvailable.tr(context: context);
case 17:
return LocaleKeys.resultsAvailable.tr(context: context);
default:
return "";
}
}
Color getLabOrderStatusColor(num status) {
switch (status) {
case 44:
return AppColors.warningColorYellow;
case 45:
return AppColors.warningColorYellow;
case 16:
return AppColors.successColor;
case 17:
return AppColors.successColor;
default:
return AppColors.greyColor;
}
}
}

@ -4,6 +4,7 @@ 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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/input_widget.dart';
@ -48,74 +49,75 @@ class _SearchLabResultsContentState extends State<SearchLabResultsContent> {
});
} else {
setState(() {
filteredSuggestions = widget.labSuggestionsList
.where((suggestion) => suggestion.toLowerCase().contains(query))
.toList();
filteredSuggestions = widget.labSuggestionsList.where((suggestion) => suggestion.toLowerCase().contains(query)).toList();
});
}
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: "Search lab results",
hintText: "Type test name",
controller: searchEditingController,
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
return CollapsingListView(
title: LocaleKeys.labResults.tr(),
isClose: true,
bottomChild: Container(
color: Colors.white,
padding: EdgeInsets.all(ResponsiveExtension(20).h),
child: CustomButton(
text: LocaleKeys.search.tr(),
icon: AppAssets.search_icon,
iconColor: Colors.white,
onPressed: () => Navigator.pop(context, searchEditingController.text),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 24, right: 24, top: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: "Search lab results",
hintText: "Type test name",
controller: searchEditingController,
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
),
),
SizedBox(height: ResponsiveExtension(20).h),
if (filteredSuggestions.isNotEmpty) ...[
"Suggestions".toText16(isBold: true),
const SizedBox(height: 12),
SizedBox(height: ResponsiveExtension(20).h),
if (filteredSuggestions.isNotEmpty) ...[
"Suggestions".toText16(isBold: true),
],
],
],
),
),
),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24, top: 16),
child: Wrap(
alignment: WrapAlignment.start,
spacing: 10,
runSpacing: 10,
children: filteredSuggestions
.map((label) => SuggestionChip(
label: label,
onTap: () {
searchEditingController.text = label;
},
))
label: label,
onTap: () {
searchEditingController.text = label;
},
))
.toList(),
),
),
),
Container(
color: Colors.white,
padding: EdgeInsets.all(ResponsiveExtension(20).h),
child: CustomButton(
text: LocaleKeys.search.tr(),
icon: AppAssets.search_icon,
iconColor: Colors.white,
onPressed: () => Navigator.pop(context, searchEditingController.text),
),
),
],
],
),
);
}
}
@ -141,10 +143,6 @@ class SuggestionChip extends StatelessWidget {
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColors.greyColor,
width: 1,
),
),
child: label.toText12(
color: isSelected ? Colors.white : Colors.black87,
@ -153,4 +151,4 @@ class SuggestionChip extends StatelessWidget {
),
);
}
}
}

@ -47,6 +47,7 @@ class AppTheme {
color: Colors.grey[800],
),
systemOverlayStyle: SystemUiOverlayStyle.light,
surfaceTintColor: Colors.transparent,
),
);
}

@ -44,10 +44,12 @@ class AppCustomChipWidget extends StatelessWidget {
avatar: icon.isNotEmpty ? Utils.buildSvgWithAssets(icon: icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor) : SizedBox.shrink(),
label: labelText!.toText10(weight: FontWeight.w500, letterSpacing: -0.64, color: textColor),
padding: EdgeInsets.all(0.0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
labelPadding: EdgeInsets.only(left: -4.h, right: 8.h),
backgroundColor: backgroundColor,
)
: Chip(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
label: labelText!.toText10(weight: FontWeight.w500, letterSpacing: -0.64, color: textColor),
padding: EdgeInsets.all(0.0),
backgroundColor: backgroundColor,

@ -126,7 +126,7 @@ void showCommonBottomSheetWithoutHeight(
top: false,
left: false,
right: false,
child: Container(
child:isCloseButtonVisible ? Container(
padding: EdgeInsets.only(left: 24, top: 24, right: 24, bottom: 12),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.bottomSheetBgColor, borderRadius: 24.h),
child: Column(
@ -144,7 +144,7 @@ void showCommonBottomSheetWithoutHeight(
),
child,
],
)),
)) : child,
);
}).then((value) {
callBackFunc();

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
class LoaderBottomSheet {
static final NavigationService _navService = GetIt.I<NavigationService>();
static bool _isVisible = false;
static void showLoader() {
if (_isVisible) return;
_isVisible = true;
showModalBottomSheet(
context: _navService.navigatorKey.currentContext!,
isDismissible: false,
enableDrag: false,
backgroundColor: Colors.transparent,
builder: (_) {
return Container(
height: MediaQuery.of(_navService.navigatorKey.currentContext!).size.height * 0.3,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: Center(
child: Utils.getLoadingWidget(),
),
);
},
).whenComplete(() {
// reset state if dismissed by system
_isVisible = false;
});
}
static void hideLoader() {
if (_isVisible) {
Navigator.of(_navService.navigatorKey.currentContext!).pop();
_isVisible = false;
}
}
}
Loading…
Cancel
Save