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 { class ApiConsts {
static const maxSmallScreen = 660; 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 // 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 insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI';
static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo';
static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo';
static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege'; static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege';
static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration'; static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration';
// static values for Api // static values for Api
static final double appVersionID = 18.7; 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_location_icon = '$svgBasePath/checkin_location_icon.svg';
static const String checkin_nfc_icon = '$svgBasePath/checkin_nfc_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 checkin_qr_icon = '$svgBasePath/checkin_qr_icon.svg';
static const String logout = '$svgBasePath/logout.svg';
//bottom navigation// //bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg'; static const String homeBottom = '$svgBasePath/home_bottom.svg';

@ -39,13 +39,15 @@ extension WidgetExtensions on Widget {
child: this, 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( ? Shimmer.fromColors(
baseColor: const Color(0xffe8eff0), baseColor: const Color(0xffe8eff0),
highlightColor: Colors.white, highlightColor: Colors.white,
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(radius), borderRadius: BorderRadius.circular(radius),
child: Container( child: Container(
width: width,
height: height,
color: Colors.white, color: Colors.white,
child: this, child: this,
), ),

@ -37,6 +37,8 @@ abstract class AuthenticationRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientIMEIData({required dynamic patientIMEIDataRequest}); Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientIMEIData({required dynamic patientIMEIDataRequest});
Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientDeviceData({required dynamic patientDeviceDataRequest}); Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientDeviceData({required dynamic patientDeviceDataRequest});
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientDeviceData({required dynamic patientDeviceDataRequest});
} }
class AuthenticationRepoImp implements AuthenticationRepo { class AuthenticationRepoImp implements AuthenticationRepo {
@ -490,4 +492,39 @@ class AuthenticationRepoImp implements AuthenticationRepo {
return Future.value(Left(UnknownFailure(e.toString()))); 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/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/localauth_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/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 '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/insert_patient_mobile_deviceinfo.dart';
import 'models/request_models/patient_insert_device_imei_request.dart'; import 'models/request_models/patient_insert_device_imei_request.dart';
@ -80,10 +82,11 @@ class AuthenticationViewModel extends ChangeNotifier {
String errorMsg = ''; String errorMsg = '';
final FocusNode myFocusNode = FocusNode(); final FocusNode myFocusNode = FocusNode();
var healthId; var healthId;
int getDeviceLastLogin =1;
Future<void> onLoginPressed() async { Future<void> onLoginPressed() async {
try { try {
LoadingUtils.showFullScreenLoader(); LoaderBottomSheet.showLoader();
//TODO: We will remove this delay //TODO: We will remove this delay
// await Future.delayed(Duration(seconds: 3)); // await Future.delayed(Duration(seconds: 3));
var data = _appState.getSelectDeviceByImeiRespModelElement; var data = _appState.getSelectDeviceByImeiRespModelElement;
@ -95,7 +98,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
} catch (e) { } catch (e) {
log("Error in onLoginPressed: $e"); log("Error in onLoginPressed: $e");
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {}); _dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {});
} }
} }
@ -192,7 +195,7 @@ class AuthenticationViewModel extends ChangeNotifier {
(failure) async { (failure) async {
// LoadingUtils.hideFullScreenLoader(); // LoadingUtils.hideFullScreenLoader();
// await _errorHandlerService.handleError(failure: failure); // await _errorHandlerService.handleError(failure: failure);
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
}, },
(apiResponse) { (apiResponse) {
@ -211,7 +214,7 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> _handleExistingImeiData(dynamic data) async { Future<void> _handleExistingImeiData(dynamic data) async {
try { try {
SelectDeviceByImeiRespModelElement? savedData = _appState.getSelectDeviceByImeiRespModelElement; SelectDeviceByImeiRespModelElement? savedData = _appState.getSelectDeviceByImeiRespModelElement;
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
if (savedData != null) { if (savedData != null) {
// TODO: Navigate to SavedLogin when available // TODO: Navigate to SavedLogin when available
@ -220,7 +223,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
} catch (e) { } catch (e) {
log("Error handling existing IMEI data: $e"); log("Error handling existing IMEI data: $e");
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
} }
} }
@ -231,7 +234,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (respData != null) { if (respData != null) {
dynamic data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson()); dynamic data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
_appState.setSelectDeviceByImeiRespModelElement(data); _appState.setSelectDeviceByImeiRespModelElement(data);
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
// TODO: Navigate to SavedLogin when available // TODO: Navigate to SavedLogin when available
// SelectDeviceByImeiRespModelElement savedData = // SelectDeviceByImeiRespModelElement savedData =
@ -239,16 +242,17 @@ class AuthenticationViewModel extends ChangeNotifier {
_navigationService.pushPage(page: SavedLogin()); _navigationService.pushPage(page: SavedLogin());
// _navigationService.pushPage(page: LoginScreen()); // _navigationService.pushPage(page: LoginScreen());
} else { } else {
LoadingUtils.hideFullScreenLoader(); print("print login........");
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
} }
} catch (e) { } catch (e) {
log("Error processing IMEI registration response: $e"); log("Error processing IMEI registration response: $e");
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
} }
}, onError: (String error) { }, onError: (String error) {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_dialogService.showErrorBottomSheet(message: error, onOkPressed: () {}); _dialogService.showErrorBottomSheet(message: error, onOkPressed: () {});
}); });
} }
@ -269,8 +273,8 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!isValidated) { if (!isValidated) {
return; return;
} }
LoaderBottomSheet.showLoader();
LoadingUtils.showFullScreenLoader(); // LoadingUtils.showFullScreenLoader();
dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest( dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest(
phoneNumber: phoneNumberController.text, phoneNumber: phoneNumberController.text,
@ -283,20 +287,22 @@ class AuthenticationViewModel extends ChangeNotifier {
calenderType: calenderType); calenderType: calenderType);
final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
LoadingUtils.hideFullScreenLoader();
result.fold( result.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure), (failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async { (apiResponse) async {
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {}); await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['isSMSSent']) { if (apiResponse.data['isSMSSent']) {
_appState.setAppAuthToken = apiResponse.data['LogInTokenID']; _appState.setAppAuthToken = apiResponse.data['LogInTokenID'];
sendActivationCode( await sendActivationCode(
otpTypeEnum: otpTypeEnum, otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text, phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text, nationalIdOrFileNumber: nationalIdController.text,
); );
} else { } else {
if (apiResponse.data['IsAuthenticated']) { if (apiResponse.data['IsAuthenticated']) {
await checkActivationCode( await checkActivationCode(
@ -304,6 +310,7 @@ class AuthenticationViewModel extends ChangeNotifier {
onWrongActivationCode: (String? message) {}, onWrongActivationCode: (String? message) {},
activationCode: null, //todo silent login case halded on the repo itself.. 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), (failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async { (apiResponse) async {
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty"); await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty");
} else { } else {
if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) { if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) {
LoaderBottomSheet.hideLoader();
navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber); navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
} else { } else {
// TODO: Handle isSMSSent false // TODO: Handle isSMSSent false
@ -375,8 +384,8 @@ class AuthenticationViewModel extends ChangeNotifier {
countryCode: selectedCountrySignup.countryCode, countryCode: selectedCountrySignup.countryCode,
loginType: loginTypeEnum.toInt) loginType: loginTypeEnum.toInt)
.toJson(); .toJson();
LoaderBottomSheet.showLoader();
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == 1) ? true : false; bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true);
if (isForRegister) { if (isForRegister) {
if (_appState.getUserRegistrationPayload.patientOutSa == 0) request['DOB'] = _appState.getUserRegistrationPayload.dob; if (_appState.getUserRegistrationPayload.patientOutSa == 0) request['DOB'] = _appState.getUserRegistrationPayload.dob;
request['HealthId'] = _appState.getUserRegistrationPayload.healthId; 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); final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: request, activationCode: activationCode.toString(), isRegister: true);
LoaderBottomSheet.hideLoader();
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) { resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>); final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (_appState.getUserRegistrationPayload.isRegister == true) { if (_appState.getUserRegistrationPayload.isRegister == true) {
@ -413,19 +424,26 @@ class AuthenticationViewModel extends ChangeNotifier {
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>); final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (activation.errorCode == '699') { if (activation.errorCode == '699') {
// Todo: Hide Loader // Todo: Hide Loader
// GifLoaderDialogUtils.hideDialog(context); // GifLoaderDialogUtils.hideDialog(context);
LoaderBottomSheet.hideLoader();
onWrongActivationCode(activation.errorEndUserMessage); onWrongActivationCode(activation.errorEndUserMessage);
return; return;
} else if (activation.messageStatus == 2) { } else if (activation.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
onWrongActivationCode(activation.errorEndUserMessage); onWrongActivationCode(activation.errorEndUserMessage);
return; return;
} else if (_appState.getUserRegistrationPayload.isRegister == true) { } else if (_appState.getUserRegistrationPayload.isRegister == true) {
LoaderBottomSheet.hideLoader();
_navigationService.pushAndReplace(AppRoutes.registerStepTwo); _navigationService.pushAndReplace(AppRoutes.registerStepTwo);
// Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)); // Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
return; return;
} else { } else {
if (activation.list != null && activation.list!.isNotEmpty) { if (activation.list != null && activation.list!.isNotEmpty) {
_appState.setAuthenticatedUser(activation.list!.first); _appState.setAuthenticatedUser(activation.list!.first);
} }
@ -433,6 +451,12 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setAppAuthToken = activation.authenticationTokenId; _appState.setAppAuthToken = activation.authenticationTokenId;
final request = RequestUtils.getAuthanticatedCommonRequest().toJson(); final request = RequestUtils.getAuthanticatedCommonRequest().toJson();
bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request); 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); insertPatientIMEIData(loginTypeEnum.toInt);
clearDefaultInputValues(); clearDefaultInputValues();
if (isUserAgreedBefore) { if (isUserAgreedBefore) {
@ -519,20 +543,22 @@ class AuthenticationViewModel extends ChangeNotifier {
await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {}); await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {});
} }
loginWithFingerPrintFace() async { loginWithFingerPrintFace(Function success) async {
_localAuthService.authenticate().then((value) async { _localAuthService.authenticate().then((value) async {
if (value) { if (value) {
// we have to handle this if verification true; LoaderBottomSheet.showLoader();
success();
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
if (!_appState.isAuthenticated) { if (!_appState.isAuthenticated) {
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint); //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
print(loginTypeEnum); // await getPatientDeviceData(loginTypeEnum.toInt);
checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {}); await checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
insertPatientIMEIData((_appState.deviceTypeID == 1 ? LoginTypeEnum.face.toInt : LoginTypeEnum.fingerprint.toInt)); await insertPatientIMEIData(loginTypeEnum.toInt);
} else { } else {
// authenticated = true; // authenticated = true;
insertPatientIMEIData((_appState.deviceTypeID == 1 ? LoginTypeEnum.face.toInt : LoginTypeEnum.fingerprint.toInt)); await insertPatientIMEIData(loginTypeEnum.toInt);
} }
LoaderBottomSheet.hideLoader();
notifyListeners(); notifyListeners();
// navigateToHomeScreen(); // navigateToHomeScreen();
} else { } else {
@ -740,6 +766,7 @@ class AuthenticationViewModel extends ChangeNotifier {
deviceTypeId: _appState.getDeviceTypeID(), deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!, patientId: _appState.getAuthenticatedUser()!.patientId!,
patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
firstName: _appState.getAuthenticatedUser()!.firstName!, firstName: _appState.getAuthenticatedUser()!.firstName!,
lastName: _appState.getAuthenticatedUser()!.lastName!, lastName: _appState.getAuthenticatedUser()!.lastName!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType, patientTypeId: _appState.getAuthenticatedUser()!.patientType,
@ -786,6 +813,33 @@ class AuthenticationViewModel extends ChangeNotifier {
log("Insert IMEI Failed"); 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 @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/material.dart';
import 'package:flutter_svg/flutter_svg.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/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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.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/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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -22,6 +24,7 @@ class _QuickLogin extends State<QuickLogin> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
NavigationService navigationService = getIt.get<NavigationService>();
return Container( return Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.white, color: Colors.white,
@ -43,7 +46,7 @@ class _QuickLogin extends State<QuickLogin> {
children: [ children: [
InkWell( InkWell(
onTap: () { onTap: () {
Navigator.pop(context, true); navigationService.pop();
}, },
child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle)), child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle)),
], ],
@ -101,9 +104,6 @@ class _QuickLogin extends State<QuickLogin> {
text:LocaleKeys.enableQuickLogin.tr(), text:LocaleKeys.enableQuickLogin.tr(),
onPressed: () { onPressed: () {
widget.onPressed(); widget.onPressed();
setState(() {
});
}, },
backgroundColor: Color(0xffED1C2B), backgroundColor: Color(0xffED1C2B),
borderColor: Color(0xffED1C2B), borderColor: Color(0xffED1C2B),

@ -42,7 +42,7 @@ class _SavedLogin extends State<SavedLogin> {
authVm.nationalIdController.text = appState.getSelectDeviceByImeiRespModelElement!.identificationNo!; authVm.nationalIdController.text = appState.getSelectDeviceByImeiRespModelElement!.identificationNo!;
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(); authVm.loginWithFingerPrintFace((){});
} }
super.initState(); super.initState();
@ -101,7 +101,7 @@ class _SavedLogin extends State<SavedLogin> {
text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}", text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
onPressed: () { onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(); authVm.loginWithFingerPrintFace((){});
} else { } else {
// int? val = loginType.toInt; // int? val = loginType.toInt;
authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp);
@ -114,7 +114,8 @@ class _SavedLogin extends State<SavedLogin> {
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
borderRadius: 12, borderRadius: 12,
padding: EdgeInsets.fromLTRB(0, 10, 0, 10), 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, textColor: AppColors.textColor,
borderWidth: 2, borderWidth: 2,
padding: EdgeInsets.fromLTRB(0, 14, 0, 14), padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
icon: AppAssets.password_validation, icon: AppAssets.sms,
iconColor: AppColors.textColor,
) )
: Container(), : Container(),
SizedBox( SizedBox(
@ -224,7 +226,7 @@ class _SavedLogin extends State<SavedLogin> {
iconColor: null, iconColor: null,
onPressed: () { onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(); authVm.loginWithFingerPrintFace((){});
} else { } else {
loginType = LoginTypeEnum.whatsapp; loginType = LoginTypeEnum.whatsapp;
int? val = loginType.toInt; 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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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/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:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -35,14 +36,14 @@ class LandingPage extends StatefulWidget {
class _LandingPageState extends State<LandingPage> { class _LandingPageState extends State<LandingPage> {
late final AuthenticationViewModel authVM; late final AuthenticationViewModel authVM;
bool isDone = false;
@override @override
void initState() { void initState() {
authVM = context.read<AuthenticationViewModel>(); authVM = context.read<AuthenticationViewModel>();
authVM.savePushTokenToAppState(); authVM.savePushTokenToAppState();
if (mounted) { if (mounted) {
authVM.checkLastLoginStatus(() { authVM.checkLastLoginStatus(() {
showQuickLogin(context, false); showQuickLogin(context);
}); });
} }
super.initState(); super.initState();
@ -321,20 +322,33 @@ class _LandingPageState extends State<LandingPage> {
); );
} }
void showQuickLogin(BuildContext context, bool isDone) { void showQuickLogin(BuildContext context) {
showCommonBottomSheet( showCommonBottomSheetWithoutHeight(
context, context,
title: "", title: "",
child: QuickLogin( isCloseButtonVisible: false,
child:
StatefulBuilder(
builder: (context, setState) {
return QuickLogin(
isDone: isDone, isDone: isDone,
onPressed: () { onPressed: () {
// sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true); // 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, isFullScreen: false,
callBackFunc: (str) { callBackFunc: () {
isDone = true; isDone = true;
setState(() {}); 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 'dart:async';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/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/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.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/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.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/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 'package:provider/provider.dart';
import 'collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget { class LabOrdersPage extends StatefulWidget {
const LabOrdersPage({super.key}); const LabOrdersPage({super.key});
@ -32,7 +27,8 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
late LabViewModel labProvider; late LabViewModel labProvider;
List<List<TestDetails>?> labSuggestions = []; List<List<TestDetails>?> labSuggestions = [];
int? expandedIndex; int? expandedIndex;
String? selectedFilterText=''; String? selectedFilterText = '';
@override @override
void initState() { void initState() {
scheduleMicrotask(() { scheduleMicrotask(() {
@ -45,214 +41,75 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
labProvider = Provider.of<LabViewModel>(context); labProvider = Provider.of<LabViewModel>(context);
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.labResults.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
), body: CollapsingListView(
body: Padding( title: LocaleKeys.labResults.tr(),
padding: EdgeInsets.all(24.h), search: () async {
child: SingleChildScrollView( final lavVM = Provider.of<LabViewModel>(context, listen: false);
child: Consumer<LabViewModel>( if (lavVM.isLabOrdersLoading) {
builder: (context, model, child) { return;
return Column( } else {
crossAxisAlignment: CrossAxisAlignment.start, String? value = await Navigator.of(context).push(CupertinoPageRoute(fullscreenDialog: true, builder: (context) => SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions)));
children: [ if (value != null) {
Row( selectedFilterText = value;
mainAxisAlignment: MainAxisAlignment.spaceBetween, lavVM.filterLabReports(value);
children: [ }
LocaleKeys.labResults.tr(context: context).toText24(isBold: true), }
Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(() { },
if (model.isLabOrdersLoading) { child: SingleChildScrollView(
return; padding: EdgeInsets.all(24),
}else { physics: NeverScrollableScrollPhysics(),
child: Consumer<LabViewModel>(
showCommonBottomSheet(context, child: SearchLabResultsContent(labSuggestionsList: model.labSuggestions), builder: (context, model, child) {
callBackFunc: (value) { return Column(
selectedFilterText = value; crossAxisAlignment: CrossAxisAlignment.start,
model.filterLabReports(value!); children: [
}, selectedFilterText!.isNotEmpty
title: LocaleKeys.searchLabReport.tr(), ? CustomChipWidget(
height: ResponsiveExtension.screenHeight, chipText: selectedFilterText!,
isFullScreen: true, chipType: ChipTypeEnum.alert,
isCloseButtonVisible: true); isSelected: true,
} )
}), : SizedBox(),
], ListView.builder(
), shrinkWrap: true,
SizedBox(height: 16.h), physics: NeverScrollableScrollPhysics(),
// Build Tab Bar padding: EdgeInsets.zero,
SizedBox(height: 16.h), itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
// Expandable list itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
selectedFilterText!.isNotEmpty ? CustomChipWidget(chipText: selectedFilterText!, chipType: ChipTypeEnum.alert, isSelected: true, ) : SizedBox(), return model.isLabOrdersLoading
ListView.builder( ? LabResultItemView(
shrinkWrap: true, onTap: () {},
physics: NeverScrollableScrollPhysics(), labOrder: null,
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length, index: index,
itemBuilder: (context, index) { isLoading: true,
final isExpanded = expandedIndex == index; )
return model.isLabOrdersLoading : AnimationConfiguration.staggeredList(
? const MoviesShimmerWidget() position: index,
: AnimationConfiguration.staggeredList( duration: const Duration(milliseconds: 500),
position: index, child: SlideAnimation(
duration: const Duration(milliseconds: 500), verticalOffset: 100.0,
child: SlideAnimation( child: FadeInAnimation(
verticalOffset: 100.0, child: LabResultItemView(
child: FadeInAnimation( onTap: () {
child: AnimatedContainer( setState(() {
duration: Duration(milliseconds: 300), expandedIndex = isExpanded ? null : index;
curve: Curves.easeInOut, });
margin: EdgeInsets.symmetric(vertical: 8.h), },
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), labOrder: model.patientLabOrders[index],
child: InkWell( index: index,
onTap: () { isExpanded: isExpanded)),
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)),
),
],
),
),
),
), ),
), );
); },
}, ),
), ],
], );
); },
}, ),
), ),
), ));
),
);
} }
Color getLabOrderStatusColor(num status) { 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/core/app_export.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.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/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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart';
@ -48,74 +49,75 @@ class _SearchLabResultsContentState extends State<SearchLabResultsContent> {
}); });
} else { } else {
setState(() { setState(() {
filteredSuggestions = widget.labSuggestionsList filteredSuggestions = widget.labSuggestionsList.where((suggestion) => suggestion.toLowerCase().contains(query)).toList();
.where((suggestion) => suggestion.toLowerCase().contains(query))
.toList();
}); });
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return CollapsingListView(
crossAxisAlignment: CrossAxisAlignment.start, title: LocaleKeys.labResults.tr(),
children: [ isClose: true,
Padding( bottomChild: Container(
padding: const EdgeInsets.symmetric(horizontal: 16), color: Colors.white,
child: Column( padding: EdgeInsets.all(ResponsiveExtension(20).h),
crossAxisAlignment: CrossAxisAlignment.start, child: CustomButton(
children: [ text: LocaleKeys.search.tr(),
TextInputWidget( icon: AppAssets.search_icon,
labelText: "Search lab results", iconColor: Colors.white,
hintText: "Type test name", onPressed: () => Navigator.pop(context, searchEditingController.text),
controller: searchEditingController, ),
isEnable: true, ),
prefix: null, child: Column(
autoFocus: false, mainAxisSize: MainAxisSize.min,
isBorderAllowed: false, crossAxisAlignment: CrossAxisAlignment.start,
keyboardType: TextInputType.text, children: [
padding: EdgeInsets.symmetric( Padding(
vertical: ResponsiveExtension(10).h, padding: const EdgeInsets.only(left: 24, right: 24, top: 24),
horizontal: ResponsiveExtension(15).h, 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),
SizedBox(height: ResponsiveExtension(20).h), if (filteredSuggestions.isNotEmpty) ...[
if (filteredSuggestions.isNotEmpty) ...[ "Suggestions".toText16(isBold: true),
"Suggestions".toText16(isBold: true), ],
const SizedBox(height: 12),
], ],
], ),
), ),
), SingleChildScrollView(
Expanded( physics: NeverScrollableScrollPhysics(),
child: SingleChildScrollView( padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24, top: 16),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Wrap( child: Wrap(
alignment: WrapAlignment.start, alignment: WrapAlignment.start,
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
children: filteredSuggestions children: filteredSuggestions
.map((label) => SuggestionChip( .map((label) => SuggestionChip(
label: label, label: label,
onTap: () { onTap: () {
searchEditingController.text = label; searchEditingController.text = label;
}, },
)) ))
.toList(), .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( decoration: BoxDecoration(
color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor, color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColors.greyColor,
width: 1,
),
), ),
child: label.toText12( child: label.toText12(
color: isSelected ? Colors.white : Colors.black87, color: isSelected ? Colors.white : Colors.black87,
@ -153,4 +151,4 @@ class SuggestionChip extends StatelessWidget {
), ),
); );
} }
} }

@ -47,6 +47,7 @@ class AppTheme {
color: Colors.grey[800], color: Colors.grey[800],
), ),
systemOverlayStyle: SystemUiOverlayStyle.light, 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(), 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), label: labelText!.toText10(weight: FontWeight.w500, letterSpacing: -0.64, color: textColor),
padding: EdgeInsets.all(0.0), padding: EdgeInsets.all(0.0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
labelPadding: EdgeInsets.only(left: -4.h, right: 8.h), labelPadding: EdgeInsets.only(left: -4.h, right: 8.h),
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
) )
: Chip( : Chip(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
label: labelText!.toText10(weight: FontWeight.w500, letterSpacing: -0.64, color: textColor), label: labelText!.toText10(weight: FontWeight.w500, letterSpacing: -0.64, color: textColor),
padding: EdgeInsets.all(0.0), padding: EdgeInsets.all(0.0),
backgroundColor: backgroundColor, backgroundColor: backgroundColor,

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