diff --git a/assets/images/svg/logout.svg b/assets/images/svg/logout.svg
new file mode 100644
index 0000000..b52e142
--- /dev/null
+++ b/assets/images/svg/logout.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index a603cf9..bad2e4c 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -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;
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index a2cbc49..d0acea0 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -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';
diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart
index f576d0c..1136c32 100644
--- a/lib/extensions/widget_extensions.dart
+++ b/lib/extensions/widget_extensions.dart
@@ -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,
),
diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart
index 22ca90f..f3f4119 100644
--- a/lib/features/authentication/authentication_repo.dart
+++ b/lib/features/authentication/authentication_repo.dart
@@ -37,6 +37,8 @@ abstract class AuthenticationRepo {
Future>> insertPatientIMEIData({required dynamic patientIMEIDataRequest});
Future>> insertPatientDeviceData({required dynamic patientDeviceDataRequest});
+
+ Future>> 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> getPatientDeviceData({required patientDeviceDataRequest}) {
+ try {
+ GenericApiModel? 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(
+ 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())));
+ }
+
+
+ }
}
diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart
index 0cf38f5..95f821f 100644
--- a/lib/features/authentication/authentication_view_model.dart
+++ b/lib/features/authentication/authentication_view_model.dart
@@ -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 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 _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);
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);
+
+
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 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
diff --git a/lib/features/authentication/models/request_models/get_user_mobile_device_data.dart b/lib/features/authentication/models/request_models/get_user_mobile_device_data.dart
new file mode 100644
index 0000000..270f3ac
--- /dev/null
+++ b/lib/features/authentication/models/request_models/get_user_mobile_device_data.dart
@@ -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 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 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,
+ };
+}
diff --git a/lib/presentation/authentication/quick_login.dart b/lib/presentation/authentication/quick_login.dart
index ff70dab..a370fb4 100644
--- a/lib/presentation/authentication/quick_login.dart
+++ b/lib/presentation/authentication/quick_login.dart
@@ -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 {
@override
Widget build(BuildContext context) {
+ NavigationService navigationService = getIt.get();
return Container(
decoration: const BoxDecoration(
color: Colors.white,
@@ -43,7 +46,7 @@ class _QuickLogin extends State {
children: [
InkWell(
onTap: () {
- Navigator.pop(context, true);
+ navigationService.pop();
},
child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle)),
],
@@ -101,9 +104,6 @@ class _QuickLogin extends State {
text:LocaleKeys.enableQuickLogin.tr(),
onPressed: () {
widget.onPressed();
- setState(() {
-
- });
},
backgroundColor: Color(0xffED1C2B),
borderColor: Color(0xffED1C2B),
diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart
index 589616f..edfc1e7 100644
--- a/lib/presentation/authentication/saved_login_screen.dart
+++ b/lib/presentation/authentication/saved_login_screen.dart
@@ -42,7 +42,7 @@ class _SavedLogin extends State {
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 {
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 {
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 {
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 {
iconColor: null,
onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
- authVm.loginWithFingerPrintFace();
+ authVm.loginWithFingerPrintFace((){});
} else {
loginType = LoginTypeEnum.whatsapp;
int? val = loginType.toInt;
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index 55afffe..58aff04 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -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 {
late final AuthenticationViewModel authVM;
-
+ bool isDone = false;
@override
void initState() {
authVM = context.read();
authVM.savePushTokenToAppState();
if (mounted) {
authVM.checkLastLoginStatus(() {
- showQuickLogin(context, false);
+ showQuickLogin(context);
});
}
super.initState();
@@ -321,20 +322,33 @@ class _LandingPageState extends State {
);
}
- 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(() {});
},
diff --git a/lib/presentation/lab/collapsing_list_view.dart b/lib/presentation/lab/collapsing_list_view.dart
new file mode 100644
index 0000000..c7f1540
--- /dev/null
+++ b/lib/presentation/lab/collapsing_list_view.dart
@@ -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,
+ )!,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart
index 4705a2a..2c6a131 100644
--- a/lib/presentation/lab/lab_orders_page.dart
+++ b/lib/presentation/lab/lab_orders_page.dart
@@ -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 {
late LabViewModel labProvider;
List?> labSuggestions = [];
int? expandedIndex;
- String? selectedFilterText='';
+ String? selectedFilterText = '';
+
@override
void initState() {
scheduleMicrotask(() {
@@ -45,214 +41,75 @@ class _LabOrdersPageState extends State {
Widget build(BuildContext context) {
labProvider = Provider.of(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(
- 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 animation) {
- return FadeTransition(
- opacity: animation,
- child: SizeTransition(
- sizeFactor: animation,
- axisAlignment: 0.0,
- child: child,
- ),
- );
- },
- child: isExpanded
- ? Container(
- key: ValueKey(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(-index)),
- ),
- ],
- ),
- ),
- ),
+ body: CollapsingListView(
+ title: LocaleKeys.labResults.tr(),
+ search: () async {
+ final lavVM = Provider.of(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(
+ 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) {
diff --git a/lib/presentation/lab/lab_result_item_view.dart b/lib/presentation/lab/lab_result_item_view.dart
new file mode 100644
index 0000000..03f721e
--- /dev/null
+++ b/lib/presentation/lab/lab_result_item_view.dart
@@ -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 animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(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(-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;
+ }
+ }
+}
diff --git a/lib/presentation/lab/search_lab_report.dart b/lib/presentation/lab/search_lab_report.dart
index e5b52e0..1b47a55 100644
--- a/lib/presentation/lab/search_lab_report.dart
+++ b/lib/presentation/lab/search_lab_report.dart
@@ -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 {
});
} 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 {
),
);
}
-}
\ No newline at end of file
+}
diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart
index 45d2ddf..ed103e5 100644
--- a/lib/theme/app_theme.dart
+++ b/lib/theme/app_theme.dart
@@ -47,6 +47,7 @@ class AppTheme {
color: Colors.grey[800],
),
systemOverlayStyle: SystemUiOverlayStyle.light,
+ surfaceTintColor: Colors.transparent,
),
);
}
diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart
index ee5dfc4..203cb86 100644
--- a/lib/widgets/chip/app_custom_chip_widget.dart
+++ b/lib/widgets/chip/app_custom_chip_widget.dart
@@ -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,
diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart
index f156fe4..cc0c03b 100644
--- a/lib/widgets/common_bottom_sheet.dart
+++ b/lib/widgets/common_bottom_sheet.dart
@@ -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();
diff --git a/lib/widgets/loader/bottomsheet_loader.dart b/lib/widgets/loader/bottomsheet_loader.dart
new file mode 100644
index 0000000..61f7f43
--- /dev/null
+++ b/lib/widgets/loader/bottomsheet_loader.dart
@@ -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();
+ 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;
+ }
+ }
+}