diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 5b6c873..1bbbff8 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -799,6 +799,10 @@ class ApiConsts { static final String checkPatientForRegistration = 'Services/Authentication.svc/REST/CheckPatientForRegisteration'; static final String checkUserStatus= 'Services/NHIC.svc/REST/GetPatientInfo'; + static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; + static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; + + // static values for Api static final double appVersionID = 18.7; static final int appChannelId = 3; diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 21061dc..d58ffeb 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -28,6 +28,11 @@ abstract class AuthenticationRepo { Future>> checkPatientForRegistration({required dynamic commonAuthanticatedRequest}); Future>> checkUserStatus({required dynamic commonAuthanticatedRequest}); + + Future>> insertPatientIMEIData({required dynamic patientIMEIDataRequest}); + + Future>> insertPatientDeviceData({required dynamic patientDeviceDataRequest}); + } class AuthenticationRepoImp implements AuthenticationRepo { @@ -52,7 +57,14 @@ class AuthenticationRepoImp implements AuthenticationRepo { try { final list = response['Patient_SELECTDeviceIMEIbyIMEIList']; if (list == null || list.isEmpty) { - throw Exception("Device list is empty"); + //throw Exception(response); + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: null, + ); + return; } final model = SelectDeviceByImeiRespModelElement.fromJson(list[0] as Map); @@ -337,4 +349,45 @@ class AuthenticationRepoImp implements AuthenticationRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future> insertPatientIMEIData({required patientIMEIDataRequest}) { + try { + GenericApiModel? apiResponse; + Failure? failure; + return apiClient.post( + ApiConsts.insertPatientDeviceIMEIData, + body: patientIMEIDataRequest, + 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()))); + } + } + + @override + Future> insertPatientDeviceData({required patientDeviceDataRequest}) { + + // TODO: implement insertPatientDeviceData + + throw UnimplementedError(); + } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 6a2ea74..4866f61 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -26,6 +26,9 @@ 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 'models/request_models/insert_patient_mobile_deviceinfo.dart'; +import 'models/request_models/patient_insert_device_imei_request.dart'; + class AuthenticationViewModel extends ChangeNotifier { final AuthenticationRepo _authenticationRepo; final AppState _appState; @@ -59,6 +62,7 @@ class AuthenticationViewModel extends ChangeNotifier { NationalityCountries? pickedCountryByUAEUser; CalenderEnum calenderType = CalenderEnum.gregorian; + LoginTypeEnum loginTypeEnum = LoginTypeEnum.sms; //================== @@ -239,6 +243,8 @@ class AuthenticationViewModel extends ChangeNotifier { Future checkUserAuthentication({required OTPTypeEnum otpTypeEnum, Function(dynamic)? onSuccess, Function(String)? onError}) async { // TODO: THIS SHOULD BE REMOVED LATER ON AND PASSED FROM APP STATE DIRECTLY INTO API CLIENT. BECAUSE THIS API ONLY NEEDS FEW PARAMS FROM USER + loginTypeEnum = otpTypeEnum == OTPTypeEnum.sms ? LoginTypeEnum.sms : LoginTypeEnum.whatsapp; + if (phoneNumberController.text.isEmpty) { phoneNumberController.text = "504278212"; } @@ -500,12 +506,13 @@ class AuthenticationViewModel extends ChangeNotifier { await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {}); } - loginWithFingerPrintFace(int selectedOption) async { + loginWithFingerPrintFace() async { _localAuthService.authenticate().then((value) { if (value) { // we have to handle this if verification true; - checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: 0000, onWrongActivationCode: (String? message) {}); + // checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: 0000, onWrongActivationCode: (String? message) {}); // authenticated = true; + insertPatientIMEIData( OTPTypeEnum.faceIDFingerprint.toInt()); notifyListeners(); // navigateToHomeScreen(); } else { @@ -518,12 +525,22 @@ class AuthenticationViewModel extends ChangeNotifier { } checkLastLoginStatus(Function() onSuccess) async { + Future.delayed(Duration(seconds: 1), () { if (_appState.getSelectDeviceByImeiRespModelElement != null && (_appState.getSelectDeviceByImeiRespModelElement!.logInType == 1 || _appState.getSelectDeviceByImeiRespModelElement!.logInType == 4)) { - Future.delayed(Duration(seconds: 1), () { + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; + nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; onSuccess(); - }); + } else if((loginTypeEnum == LoginTypeEnum.sms || loginTypeEnum == LoginTypeEnum.whatsapp && _appState.getSelectDeviceByImeiRespModelElement == null) && _appState.getAuthenticatedUser() != null){ + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; + nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; + onSuccess(); } + }); } Future onRegisterPress({required OTPTypeEnum otpTypeEnum}) async { @@ -661,6 +678,32 @@ class AuthenticationViewModel extends ChangeNotifier { // }); } + Future insertPatientIMEIData(int loginType) async{ + + final resultEither = await _authenticationRepo.insertPatientIMEIData(patientIMEIDataRequest: PatientInsertDeviceImei(imei: _appState.deviceToken, deviceTypeId: _appState.getDeviceTypeID(), patientId: _appState.getAuthenticatedUser()!.patientId!, patientIdentificationNo:_appState.getAuthenticatedUser()!.nationalityId!, firstName: _appState.getAuthenticatedUser()!.firstName!, lastName: _appState.getAuthenticatedUser()!.lastName!, patientTypeId: _appState.getAuthenticatedUser()!.patientType, mobileNo:_appState.getAuthenticatedUser()!.mobileNumber!, logInTypeId: loginType, patientOutSa:_appState.getAuthenticatedUser()!.outSa! ).toJson()); + resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { + if (apiResponse.messageStatus == 1) { + print("Insert IMEI Success"); + insertPatientDeviceData( loginType); + } else { + print("Insert IMEI Failed"); + } + }); + + } + Future insertPatientDeviceData(int loginType) async{ + + final resultEither = await _authenticationRepo.insertPatientDeviceData(patientDeviceDataRequest: InsertPatientMobileDeviceInfo(deviceToken: _appState.deviceToken, deviceTypeId: _appState.getDeviceTypeID(), patientId: _appState.getAuthenticatedUser()!.patientId!, patientTypeId: _appState.getAuthenticatedUser()!.patientType, patientOutSa:_appState.getAuthenticatedUser()!.outSa!, loginType: loginType, languageId: _appState.getLanguageID(), latitude: _appState.userLat, longitude:_appState.userLong ).toJson()); + resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { + if (apiResponse.messageStatus == 1) { + print("Insert Device Data Success"); + } else { + print("Insert IMEI Failed"); + } + }); + + } + @override void dispose() { nationalIdController.dispose(); diff --git a/lib/features/authentication/models/request_models/insert_patient_mobile_deviceinfo.dart b/lib/features/authentication/models/request_models/insert_patient_mobile_deviceinfo.dart new file mode 100644 index 0000000..dbfb0e1 --- /dev/null +++ b/lib/features/authentication/models/request_models/insert_patient_mobile_deviceinfo.dart @@ -0,0 +1,109 @@ +import 'dart:convert'; + +class InsertPatientMobileDeviceInfo { + double? versionId; + int? channel; + int? languageId; + String? ipAdress; + String? generalid; + int? patientOutSa; + bool? isDentalAllowedBackend; + int? deviceTypeId; + int? patientId; + String? tokenId; + String? voipToken; + int? patientTypeId; + int? patientType; + String? deviceToken; + String? deviceType; + String? patientMobileNumber; + String? nationalId; + int? gender; + int? loginType; + String? macAddress; + double? latitude; + double? longitude; + String? sessionId; + + InsertPatientMobileDeviceInfo({ + this.versionId, + this.channel, + this.languageId, + this.ipAdress, + this.generalid, + this.patientOutSa, + this.isDentalAllowedBackend, + this.deviceTypeId, + this.patientId, + this.tokenId, + this.voipToken, + this.patientTypeId, + this.patientType, + this.deviceToken, + this.deviceType, + this.patientMobileNumber, + this.nationalId, + this.gender, + this.loginType, + this.macAddress, + this.latitude, + this.longitude, + this.sessionId, + }); + + factory InsertPatientMobileDeviceInfo.fromRawJson(String str) => InsertPatientMobileDeviceInfo.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory InsertPatientMobileDeviceInfo.fromJson(Map json) => InsertPatientMobileDeviceInfo( + versionId: json["VersionID"]?.toDouble(), + channel: json["Channel"], + languageId: json["LanguageID"], + ipAdress: json["IPAdress"], + generalid: json["generalid"], + patientOutSa: json["PatientOutSA"], + isDentalAllowedBackend: json["isDentalAllowedBackend"], + deviceTypeId: json["DeviceTypeID"], + patientId: json["PatientID"], + tokenId: json["TokenID"], + voipToken: json["VoipToken"], + patientTypeId: json["PatientTypeID"], + patientType: json["PatientType"], + deviceToken: json["DeviceToken"], + deviceType: json["DeviceType"], + patientMobileNumber: json["PatientMobileNumber"], + nationalId: json["NationalID"], + gender: json["Gender"], + loginType: json["LoginType"], + macAddress: json["MACAddress"], + latitude: json["Latitude"], + longitude: json["Longitude"], + sessionId: json[" SessionID"], + ); + + Map toJson() => { + "VersionID": versionId, + "Channel": channel, + "LanguageID": languageId, + "IPAdress": ipAdress, + "generalid": generalid, + "PatientOutSA": patientOutSa, + "isDentalAllowedBackend": isDentalAllowedBackend, + "DeviceTypeID": deviceTypeId, + "PatientID": patientId, + "TokenID": tokenId, + "VoipToken": voipToken, + "PatientTypeID": patientTypeId, + "PatientType": patientType, + "DeviceToken": deviceToken, + "DeviceType": deviceType, + "PatientMobileNumber": patientMobileNumber, + "NationalID": nationalId, + "Gender": gender, + "LoginType": loginType, + "MACAddress": macAddress, + "Latitude": latitude, + "Longitude": longitude, + " SessionID": sessionId, + }; +} diff --git a/lib/features/authentication/models/request_models/patient_insert_device_imei_request.dart b/lib/features/authentication/models/request_models/patient_insert_device_imei_request.dart new file mode 100644 index 0000000..f54bb83 --- /dev/null +++ b/lib/features/authentication/models/request_models/patient_insert_device_imei_request.dart @@ -0,0 +1,125 @@ +import 'dart:convert'; + +class PatientInsertDeviceImei { + String? setupId; + int? patientType; + int? patientId; + String? firstName; + String? firstNameN; + String? lastNameN; + String? lastName; + int? preferredLanguage; + String? patientIdentificationNo; + bool? outSa; + String? identificationNo; + String? mobileNo; + String? tokenId; + String? imei; + bool? biometricEnabled; + int? logInTypeId; + double? versionId; + int? channel; + int? languageId; + String? ipAdress; + String? generalid; + int? latitude; + int? longitude; + int? deviceTypeId; + int? patientTypeId; + int? patientOutSa; + String? sessionId; + + PatientInsertDeviceImei({ + this.setupId, + this.patientType, + this.patientId, + this.firstName, + this.firstNameN, + this.lastNameN, + this.lastName, + this.preferredLanguage, + this.patientIdentificationNo, + this.outSa, + this.identificationNo, + this.mobileNo, + this.tokenId, + this.imei, + this.biometricEnabled, + this.logInTypeId, + this.versionId, + this.channel, + this.languageId, + this.ipAdress, + this.generalid, + this.latitude, + this.longitude, + this.deviceTypeId, + this.patientTypeId, + this.patientOutSa, + this.sessionId, + }); + + factory PatientInsertDeviceImei.fromRawJson(String str) => PatientInsertDeviceImei.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PatientInsertDeviceImei.fromJson(Map json) => PatientInsertDeviceImei( + setupId: json["SetupID"], + patientType: json["PatientType"], + patientId: json["PatientID"], + firstName: json["FirstName"], + firstNameN: json["FirstNameN"], + lastNameN: json["LastNameN"], + lastName: json["LastName"], + preferredLanguage: json["PreferredLanguage"], + patientIdentificationNo: json["PatientIdentificationNo"], + outSa: json["OutSA"], + identificationNo: json["IdentificationNo"], + mobileNo: json["MobileNo"], + tokenId: json["TokenID"], + imei: json["IMEI"], + biometricEnabled: json["BiometricEnabled"], + logInTypeId: json["LogInTypeID"], + versionId: json["VersionID"]?.toDouble(), + channel: json["Channel"], + languageId: json["LanguageID"], + ipAdress: json["IPAdress"], + generalid: json["generalid"], + latitude: json["Latitude"], + longitude: json["Longitude"], + deviceTypeId: json["DeviceTypeID"], + patientTypeId: json["PatientTypeID"], + patientOutSa: json["PatientOutSA"], + sessionId: json[" SessionID"], + ); + + Map toJson() => { + "SetupID": setupId, + "PatientType": patientType, + "PatientID": patientId, + "FirstName": firstName, + "FirstNameN": firstNameN, + "LastNameN": lastNameN, + "LastName": lastName, + "PreferredLanguage": preferredLanguage, + "PatientIdentificationNo": patientIdentificationNo, + "OutSA": outSa, + "IdentificationNo": identificationNo, + "MobileNo": mobileNo, + "TokenID": tokenId, + "IMEI": imei, + "BiometricEnabled": biometricEnabled, + "LogInTypeID": logInTypeId, + "VersionID": versionId, + "Channel": channel, + "LanguageID": languageId, + "IPAdress": ipAdress, + "generalid": generalid, + "Latitude": latitude, + "Longitude": longitude, + "DeviceTypeID": deviceTypeId, + "PatientTypeID": patientTypeId, + "PatientOutSA": patientOutSa, + " SessionID": sessionId, + }; +} diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index f6e725a..0b463cc 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -203,6 +203,7 @@ class LoginScreenState extends State { borderColor: AppColors.borderOnlyColor, textColor: AppColors.textColor, icon: AppAssets.whatsapp, + iconColor: null, ), ), ], diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index 357daa6..3285163 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -81,7 +81,7 @@ class _SavedLogin extends State { ("${LocaleKeys.lastloginBy.tr()} ${LoginTypeExtension.fromValue(appState.getSelectDeviceByImeiRespModelElement!.logInType!)!.displayName}") .toText14(isBold: true, color: AppColors.greyTextColor), (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null - ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y at HH:mm") + ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm") : '--') .toText16(isBold: true, color: AppColors.textColor), @@ -95,7 +95,7 @@ class _SavedLogin extends State { text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}", onPressed: () { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { - authVm.loginWithFingerPrintFace(loginType.toInt); + authVm.loginWithFingerPrintFace(); } else { // int? val = loginType.toInt; authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); @@ -108,7 +108,7 @@ class _SavedLogin extends State { fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(0, 10, 0, 10), - icon: AppAssets.apple_finder, + icon: AppAssets.sms, ), ), ], @@ -165,7 +165,7 @@ class _SavedLogin extends State { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, textColor: AppColors.whiteColor, - icon: AppAssets.message, + icon: AppAssets.sms, ), ), Row( @@ -213,9 +213,11 @@ class _SavedLogin extends State { ) : CustomButton( text: "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}", + icon: AppAssets.whatsapp, + iconColor: null, onPressed: () { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { - authVm.loginWithFingerPrintFace(loginType.toInt); + authVm.loginWithFingerPrintFace(); } else { loginType = LoginTypeEnum.whatsapp; int? val = loginType.toInt; @@ -227,7 +229,7 @@ class _SavedLogin extends State { textColor: Color(0xFF2E3039), borderWidth: 2, padding: EdgeInsets.fromLTRB(0, 14, 0, 14), - icon: AppAssets.whatsapp, + ), const Spacer(flex: 2), // OR divider diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index b33658f..e569edb 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -41,7 +41,7 @@ class _LandingPageState extends State { authVM = context.read(); if (mounted) { authVM.checkLastLoginStatus(() { - // showQuickLogin(context, false); + showQuickLogin(context, false); }); } super.initState(); @@ -328,7 +328,7 @@ class _LandingPageState extends State { isDone: isDone, onPressed: () { // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true); - // loginWithFingerPrintFace(3, 1, user, deviceToken); + authVM.loginWithFingerPrintFace(); }, ), height: 400, diff --git a/lib/services/localauth_service.dart b/lib/services/localauth_service.dart index a01d1c1..2875a7f 100644 --- a/lib/services/localauth_service.dart +++ b/lib/services/localauth_service.dart @@ -6,22 +6,31 @@ class LocalAuthService { final LocalAuthentication localAuth; final LoggerService loggerService; LocalAuthService({required this.localAuth, required this.loggerService}); - Future authenticate() async { try { - bool isAuthenticated = await localAuth.authenticate( + final canCheck = await localAuth.canCheckBiometrics; + final isDeviceSupported = await localAuth.isDeviceSupported(); + + if (!canCheck || !isDeviceSupported) { + return false; + } + + final isAuthenticated = await localAuth.authenticate( localizedReason: 'Please authenticate to proceed', options: const AuthenticationOptions( biometricOnly: true, stickyAuth: true, ), ); + return isAuthenticated; } catch (e) { + print(e); return false; } } + Future canCheckBiometrics() async { try { return await localAuth.canCheckBiometrics; diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 5413cea..e1448dc 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -18,7 +18,7 @@ class CustomButton extends StatelessWidget { final String? fontFamily; final FontWeight fontWeight; final bool isDisabled; - final Color iconColor; + final Color? iconColor; final double height; final double iconSize;