diff --git a/android/app/build.gradle b/android/app/build.gradle index ae87782e..da345fc2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,6 +44,7 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true } buildTypes { @@ -72,9 +73,10 @@ dependencies { implementation 'com.opentok.android:opentok-android-sdk:2.16.5' //permissions implementation 'pub.devrel:easypermissions:0.4.0' - +implementation 'com.google.firebase:firebase-core:9.6.1' //retrofit implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1' + apply plugin: 'com.google.gms.google-services' } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 357c6a1a..ea0f0026 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.2' } } diff --git a/android/google-services.json b/android/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d454..9c0729c9 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ -org.gradle.jvmargs=-Xmx1536M + android.enableR8=true android.useAndroidX=true android.enableJetifier=true +org.gradle.jvmargs=-Xmx4608m diff --git a/assets/images/login/101.png b/assets/images/login/101.png new file mode 100644 index 00000000..90c1c575 Binary files /dev/null and b/assets/images/login/101.png differ diff --git a/assets/images/login/102.png b/assets/images/login/102.png new file mode 100644 index 00000000..8502d197 Binary files /dev/null and b/assets/images/login/102.png differ diff --git a/assets/images/login/103.png b/assets/images/login/103.png new file mode 100644 index 00000000..3326814b Binary files /dev/null and b/assets/images/login/103.png differ diff --git a/assets/images/login/104.png b/assets/images/login/104.png new file mode 100644 index 00000000..ad55ff74 Binary files /dev/null and b/assets/images/login/104.png differ diff --git a/assets/images/login/fileNum.png b/assets/images/login/fileNum.png new file mode 100644 index 00000000..386299b7 Binary files /dev/null and b/assets/images/login/fileNum.png differ diff --git a/assets/images/login/forget.png b/assets/images/login/forget.png new file mode 100644 index 00000000..57aa7ccc Binary files /dev/null and b/assets/images/login/forget.png differ diff --git a/assets/images/login/id.png b/assets/images/login/id.png new file mode 100644 index 00000000..9260cf11 Binary files /dev/null and b/assets/images/login/id.png differ diff --git a/assets/images/login/more_icon.png b/assets/images/login/more_icon.png new file mode 100644 index 00000000..b696d345 Binary files /dev/null and b/assets/images/login/more_icon.png differ diff --git a/assets/images/login/nationalID.png b/assets/images/login/nationalID.png new file mode 100644 index 00000000..5779d562 Binary files /dev/null and b/assets/images/login/nationalID.png differ diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart index 3a39c5e9..b68907d3 100644 --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -38,20 +38,19 @@ class BaseAppClient { try { Map profile = await sharedPref.getObj(DOCTOR_PROFILE); String token = await sharedPref.getString(TOKEN); - if (profile != null) { + if (profile != null) { DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile); - if (body['DoctorID'] == null) + if (body['DoctorID'] == null) body['DoctorID'] = doctorProfile?.doctorID; - if (body['DoctorID'] == "") - body['DoctorID'] = null; - body['EditedBy'] = doctorProfile?.doctorID; + if (body['DoctorID'] == "") body['DoctorID'] = null; + body['EditedBy'] = doctorProfile?.doctorID; if (body['ProjectID'] == null) { body['ProjectID'] = doctorProfile?.projectID; - } + } if (body['ClinicID'] == null) body['ClinicID'] = doctorProfile?.clinicID; - } - body['TokenID'] = token ?? ''; + } + body['TokenID'] = token ?? '@dm!n'; String lang = await sharedPref.getString(APP_Language); if (lang != null && lang == 'ar') body['LanguageID'] = 1; @@ -66,8 +65,8 @@ class BaseAppClient { body['IsLoginForDoctorApp'] = IS_LOGIN_FOR_DOCTOR_APP; body['PatientOutSA'] = 0; // PATIENT_OUT_SA; body['VidaAuthTokenID'] = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); - body['VidaRefreshTokenID'] = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); - + body['VidaRefreshTokenID'] = + await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); print("URL : $url"); print("Body : ${json.encode(body)}"); @@ -87,8 +86,7 @@ class BaseAppClient { if (!parsed['IsAuthenticated']) { await helpers.logout(); helpers.showErrorToast('Your session expired Please login agian'); - } else - if (parsed['MessageStatus'] == 1) { + } else if (parsed['MessageStatus'] == 1) { if (!parsed['IsAuthenticated']) onFailure(getError(parsed), statusCode); else @@ -123,7 +121,7 @@ class BaseAppClient { } } } - if(error == null || error == "null" || error == "null\n"){ + if (error == null || error == "null" || error == "null\n") { return "This server not work probably in this time"; } return error; diff --git a/lib/config/config.dart b/lib/config/config.dart index e3163bb2..fe4a9c03 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -78,9 +78,13 @@ const GET_PATIENT_LAB_RESULTS = 'Services/DoctorApplication.svc/REST/GetPatientLabResults'; const LOGIN_URL = 'Services/Sentry.svc/REST/MemberLogIN_New'; const INSERT_DEVICE_IMEI = - 'Services/Sentry.svc/REST/DoctorApplication_INSERTDeviceIMEI'; + 'Services/DoctorApplication.svc/REST/DoctorApp_InsertOrUpdateDeviceDetails'; +// 'Services/Sentry.svc/REST/DoctorApplication_INSERTDeviceIMEI'; +// const SELECT_DEVICE_IMEI = +// 'Services/Sentry.svc/REST/DoctorApplication_SELECTDeviceIMEIbyIMEI'; + const SELECT_DEVICE_IMEI = - 'Services/Sentry.svc/REST/DoctorApplication_SELECTDeviceIMEIbyIMEI'; + 'Services/DoctorApplication.svc/REST/DoctorApp_GetDeviceDetailsByIMEI'; const SEND_ACTIVATION_CODE_BY_OTP_NOTIFICATION_TYPE = 'Services/Sentry.svc/REST/DoctorApplication_SendActivationCodebyOTPNotificationType'; @@ -216,6 +220,8 @@ var SERVICES_PATIANT_HEADER_AR = [ //****************** // Colors ////// by : ibrahim + +var DEVICE_TOKEN = ""; const PRIMARY_COLOR = 0xff515B5D; const TRANSACTION_NO = 0; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 3048a39d..74bfdeed 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -536,4 +536,39 @@ const Map> localizedValues = { 'en': "There is no Chief Complaint", 'ar': "ليس هناك شكوى رئيس" }, + "more-verify": { + "en": "More Verification Options", + "ar": "المزيد من خيارات التحقق" + }, + "welcome-back": {"en": "Welcome back!", "ar": "مرحبا بعودتك!"}, + "account-info": { + "en": "Would you like to login with current username?", + "ar": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟" + }, + "another-acc": {"en": "Use Another Account", "ar": "استخدم حسابا آخر"}, + "verify-login-with": { + "en": "Please choose one of the following options to verify", + "ar": "الرجاء اختيار احدى الخيارات التالية للتحقق من البيانات" + }, + "register-user": {"en": "Register", "ar": "تسجيل"}, + "verify-with-fingerprint": {"en": "Fingerprint", "ar": "بصمة"}, + "verify-with-faceid": {"en": "Face ID", "ar": "معرف الوجه"}, + "verify-with-sms": {"en": "SMS", "ar": "الرسائل القصيرة"}, + "verify-with-whatsapp": {"en": "Whatsapp", "ar": " الواتس اب"}, + "last-login": {"en": "LAST LOGIN AT:", "ar": "آخر تسجيل دخول"}, + "last-login-with": {"en": "VERIFICATION TYPE:", "ar": "نوع التحقق:"}, + "verify-fingerprint": { + "en": + "To activate the fingerprint login service, please verify data by using one of the following options.", + "ar": + "لتفعيل خدمة الدخول بالبصمة، يرجى اختيار احدى القنوات التالية للتحقق من البيانات" + }, + "verification_message": { + "en": "Please enter the Verification Code sent to", + "ar": "الرجاء ادخال رمز التحقق الذي تم إرساله إلى" + }, + "validation_message": { + "en": "The verification code expires in", + "ar": "تنتهي صلاحية رمز التحقق خلال" + }, }; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index e483c7d1..1520207f 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -10,3 +10,5 @@ final DOCTOR_PROFILE = 'doctorProfile'; final LIVE_CARE_PATIENT = 'livecare-patient-profile'; final LOGGED_IN_USER = 'loggedUser'; final DASHBOARD_DATA = 'dashboard-data'; +final OTP_TYPE = 'otp-type'; +final LAST_LOGIN_USER = 'last-login-user'; diff --git a/lib/core/model/imei_details.dart b/lib/core/model/imei_details.dart new file mode 100644 index 00000000..2cb0cd97 --- /dev/null +++ b/lib/core/model/imei_details.dart @@ -0,0 +1,88 @@ +class GetIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobile; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clnicDescriptionN; + String projectName; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool biometricEnabled; + int preferredLanguage; + bool isActive; + + GetIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobile, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clnicDescriptionN, + this.projectName, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.biometricEnabled, + this.preferredLanguage, + this.isActive}); + + GetIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobile = json['Mobile']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clnicDescriptionN = json['ClnicDescriptionN']; + projectName = json['ProjectName']; + genderDescription = json['Gender_Description']; + genderDescriptionN = json['Gender_DescriptionN']; + titleDescription = json['Title_Description']; + titleDescriptionN = json['Title_DescriptionN']; + biometricEnabled = json['BiometricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['Mobile'] = this.mobile; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClnicDescriptionN'] = this.clnicDescriptionN; + data['ProjectName'] = this.projectName; + data['Gender_Description'] = this.genderDescription; + data['Gender_DescriptionN'] = this.genderDescriptionN; + data['Title_Description'] = this.titleDescription; + data['Title_DescriptionN'] = this.titleDescriptionN; + data['BiometricEnabled'] = this.biometricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/model/insert_imei_model.dart b/lib/core/model/insert_imei_model.dart new file mode 100644 index 00000000..c2285d92 --- /dev/null +++ b/lib/core/model/insert_imei_model.dart @@ -0,0 +1,92 @@ +class InsertIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobileNo; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clinicDescriptionN; + String projectName; + int projectID; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool bioMetricEnabled; + int preferredLanguage; + bool isActive; + + InsertIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobileNo, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clinicDescriptionN, + this.projectName, + this.projectID, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.bioMetricEnabled, + this.preferredLanguage, + this.isActive}); + + InsertIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobileNo = json['MobileNo']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionN = json['ClinicDescriptionN']; + projectName = json['ProjectName']; + projectID = json['ProjectID']; + genderDescription = json['GenderDescription']; + genderDescriptionN = json['GenderDescriptionN']; + titleDescription = json['TitleDescription']; + titleDescriptionN = json['TitleDescriptionN']; + bioMetricEnabled = json['BioMetricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['MobileNo'] = this.mobileNo; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ProjectName'] = this.projectName; + data['ProjectID'] = this.projectID; + data['GenderDescription'] = this.genderDescription; + data['GenderDescriptionN'] = this.genderDescriptionN; + data['TitleDescription'] = this.titleDescription; + data['TitleDescriptionN'] = this.titleDescriptionN; + data['BioMetricEnabled'] = this.bioMetricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/service/auth_service.dart b/lib/core/service/auth_service.dart new file mode 100644 index 00000000..e116ccdd --- /dev/null +++ b/lib/core/service/auth_service.dart @@ -0,0 +1,29 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/base/base_service.dart'; +import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart'; + +class AuthService extends BaseService { + List _imeiDetails = []; + List get dashboardItemsList => _imeiDetails; + + Future selectDeviceImei(imei) async { + try { + // dynamic localRes; + await baseAppClient.post(SELECT_DEVICE_IMEI, + onSuccess: (dynamic response, int statusCode) { + _imeiDetails = []; + response['List_DoctorDeviceDetails'].forEach((v) { + _imeiDetails.add(GetIMEIDetailsModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: {"IMEI": imei, "TokenID": "@dm!n"}); + //return Future.value(localRes); + } catch (error) { + hasError = true; + super.error = error; + } + } +} diff --git a/lib/core/service/medicine_service.dart b/lib/core/service/medicine_service.dart index df23172f..f205dab1 100644 --- a/lib/core/service/medicine_service.dart +++ b/lib/core/service/medicine_service.dart @@ -14,7 +14,6 @@ class MedicineService extends BaseService { PharmaciesItemsRequestModel(); PharmaciesListRequestModel _listRequestModel = PharmaciesListRequestModel(); - Future getMedicineItem(String itemName) async { _itemsRequestModel.pHRItemName = itemName; await baseAppClient.post( diff --git a/lib/core/viewModel/auth_view_model.dart b/lib/core/viewModel/auth_view_model.dart index 47ffe730..00089ef9 100644 --- a/lib/core/viewModel/auth_view_model.dart +++ b/lib/core/viewModel/auth_view_model.dart @@ -1,4 +1,10 @@ import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/model/insert_imei_model.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; @@ -12,8 +18,9 @@ import '../../models/doctor/user_model.dart'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } -class AuthViewModel with ChangeNotifier { +class AuthViewModel extends BaseViewModel { List doctorsClinicList = []; + String selectedClinicName; bool isLogin = false; bool isLoading = true; @@ -71,35 +78,29 @@ class AuthViewModel with ChangeNotifier { } } - Future insertDeviceImei(imei) async { - try { - dynamic localRes; - - await baseAppClient.post(INSERT_DEVICE_IMEI, - onSuccess: (dynamic response, int statusCode) { - localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); - return Future.value(localRes); - } catch (error) { - print(error); - throw error; - } - } + Future insertDeviceImei(request) async { + var loggedIn = await sharedPref.getObj(LOGGED_IN_USER); + + request['IMEI'] = DEVICE_TOKEN; + request['LogInTypeID'] = await sharedPref.getInt(OTP_TYPE); + request['BioMetricEnabled'] = true; + request['MobileNo'] = loggedIn['MobileNumber']; + InsertIMEIDetailsModel nRequest = InsertIMEIDetailsModel.fromJson(request); + nRequest.genderDescription = request['Gender_Description']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.titleDescription = request['Title_Description']; + nRequest.titleDescriptionN = request['Title_DescriptionN']; + nRequest.projectID = await sharedPref.getInt(PROJECT_ID); - Future selectDeviceImei(imei) async { try { - dynamic localRes; - await baseAppClient.post(SELECT_DEVICE_IMEI, + var localRes; + await baseAppClient.post(INSERT_DEVICE_IMEI, onSuccess: (dynamic response, int statusCode) { localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); + }, onFailure: (String error, int statusCode) {}, body: nRequest.toJson()); return Future.value(localRes); } catch (error) { - print(error); throw error; } } @@ -120,7 +121,8 @@ class AuthViewModel with ChangeNotifier { } } - Future sendActivationCodeForDoctorApp(ActivationCodeModel activationCodeModel) async { + Future sendActivationCodeForDoctorApp( + ActivationCodeModel activationCodeModel) async { try { var localRes; await baseAppClient.post(SEND_ACTIVATION_CODE_FOR_DOCTOR_APP, @@ -158,22 +160,22 @@ class AuthViewModel with ChangeNotifier { } } - - Future checkActivationCodeForDoctorApp(CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { + Future checkActivationCodeForDoctorApp( + CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { try { dynamic localRes; await baseAppClient.post(CHECK_ACTIVATION_CODE_FOR_DOCTOR_APP, onSuccess: (dynamic response, int statusCode) { - localRes = response; - selectedClinicName = - ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; - - response['List_DoctorsClinic'].forEach((v) { - doctorsClinicList.add(new ClinicModel.fromJson(v)); - }); - }, onFailure: (String error, int statusCode) { - throw error; - }, body: checkActivationCodeRequestModel.toJson()); + localRes = response; + selectedClinicName = + ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; + + response['List_DoctorsClinic'].forEach((v) { + doctorsClinicList.add(new ClinicModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + throw error; + }, body: checkActivationCodeRequestModel.toJson()); return Future.value(localRes); } catch (error) { print(error); diff --git a/lib/core/viewModel/imei_view_model.dart b/lib/core/viewModel/imei_view_model.dart new file mode 100644 index 00000000..29253b1d --- /dev/null +++ b/lib/core/viewModel/imei_view_model.dart @@ -0,0 +1,21 @@ +import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; + +class IMEIViewModel extends BaseViewModel { + AuthService _authService = locator(); + List get imeiDetails => _authService.dashboardItemsList; + + Future selectDeviceImei(imei) async { + setState(ViewState.Busy); + await _authService.selectDeviceImei(imei); + if (_authService.hasError) { + error = _authService.error; + setState(ViewState.Error); + } else + setState(ViewState.Idle); + } +} diff --git a/lib/core/viewModel/project_view_model.dart b/lib/core/viewModel/project_view_model.dart index 1448fb47..aed67d83 100644 --- a/lib/core/viewModel/project_view_model.dart +++ b/lib/core/viewModel/project_view_model.dart @@ -24,6 +24,7 @@ class ProjectViewModel with ChangeNotifier { List doctorClinicsList = []; bool isLoading = false; bool isError = false; + bool isLogin = false; String error = ''; BaseAppClient baseAppClient = BaseAppClient(); @@ -56,7 +57,9 @@ class ProjectViewModel with ChangeNotifier { currentLanguage = await sharedPref.getString(APP_Language); _appLocale = Locale(currentLanguage ?? 'en'); _isArabic = currentLanguage != null - ? currentLanguage == 'ar' ? true : false + ? currentLanguage == 'ar' + ? true + : false : false; notifyListeners(); } @@ -69,7 +72,7 @@ class ProjectViewModel with ChangeNotifier { sharedPref.setString(APP_Language, 'ar'); } else if (lan != "ar" && currentLanguage != lan) { _appLocale = Locale("en"); - _isArabic = false; + _isArabic = false; currentLanguage = 'en'; sharedPref.setString(APP_Language, 'en'); } diff --git a/lib/locator.dart b/lib/locator.dart index a4ca7289..f939effc 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,10 +1,13 @@ +import 'package:doctor_app_flutter/core/service/auth_service.dart'; import 'package:doctor_app_flutter/core/service/dasboard_service.dart'; import 'package:doctor_app_flutter/core/service/medical_file_service.dart'; import 'package:doctor_app_flutter/core/service/patient_service.dart'; import 'package:doctor_app_flutter/core/service/prescription_service.dart'; import 'package:doctor_app_flutter/core/service/procedure_service.dart'; import 'package:doctor_app_flutter/core/service/sickleave_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/medical_file_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart'; @@ -54,9 +57,11 @@ void setupLocator() { locator.registerLazySingleton(() => MedicalFileService()); locator.registerLazySingleton(() => AdmissionRequestService()); locator.registerLazySingleton(() => UcafService()); + locator.registerLazySingleton(() => AuthService()); /// View Model locator.registerFactory(() => DoctorReplayViewModel()); + locator.registerFactory(() => IMEIViewModel()); locator.registerFactory(() => ScheduleViewModel()); locator.registerFactory(() => ReferralPatientViewModel()); locator.registerFactory(() => ReferredPatientViewModel()); diff --git a/lib/main.dart b/lib/main.dart index 3df44a70..1283da1e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,32 +41,31 @@ class MyApp extends StatelessWidget { ), ], child: Consumer( - builder: (context,projectProvider,child) => MaterialApp( - showSemanticsDebugger: false, - title: 'Flutter Demo', - locale: projectProvider.appLocal, - localizationsDelegates: [ - TranslationBaseDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - const Locale('ar', ''), // Arabic - const Locale('en', ''), // English - ], - theme: ThemeData( - primarySwatch: Colors.grey, - primaryColor: Colors.grey, - buttonColor: HexColor('#B8382C'), - fontFamily: 'WorkSans', - dividerColor: Colors.grey[350], - backgroundColor: Color.fromRGBO(255,255,255, 1), - ), - initialRoute: INIT_ROUTE, - routes: routes, - debugShowCheckedModeBanner: false, - ) - ), + builder: (context, projectProvider, child) => MaterialApp( + showSemanticsDebugger: false, + title: 'Flutter Demo', + locale: projectProvider.appLocal, + localizationsDelegates: [ + TranslationBaseDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + const Locale('ar', ''), // Arabic + const Locale('en', ''), // English + ], + theme: ThemeData( + primarySwatch: Colors.grey, + primaryColor: Colors.grey, + buttonColor: HexColor('#B8382C'), + fontFamily: 'WorkSans', + dividerColor: Colors.grey[350], + backgroundColor: Color.fromRGBO(255, 255, 255, 1), + ), + initialRoute: INIT_ROUTE, + routes: routes, + debugShowCheckedModeBanner: false, + )), ); }); }, diff --git a/lib/models/auth/activation_Code_req_model.dart b/lib/models/auth/activation_Code_req_model.dart index f8f48cd8..1a9510e8 100644 --- a/lib/models/auth/activation_Code_req_model.dart +++ b/lib/models/auth/activation_Code_req_model.dart @@ -8,17 +8,18 @@ class ActivationCodeModel { String password; int facilityId; String generalid; - + String otpSendType; ActivationCodeModel( {this.mobileNumber, - this.zipCode, - this.channel, - this.languageID, - this.versionID, - this.memberID, - this.password, - this.facilityId, - this.generalid}); + this.zipCode, + this.channel, + this.languageID, + this.versionID, + this.memberID, + this.password, + this.facilityId, + this.otpSendType, + this.generalid}); ActivationCodeModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -29,6 +30,7 @@ class ActivationCodeModel { memberID = json['MemberID']; password = json['Password']; facilityId = json['facilityId']; + otpSendType = json['OTP_SendType']; generalid = json['generalid']; } @@ -42,6 +44,7 @@ class ActivationCodeModel { data['MemberID'] = this.memberID; data['Password'] = this.password; data['facilityId'] = this.facilityId; + data['OTP_SendType'] = otpSendType; data['generalid'] = this.generalid; return data; } diff --git a/lib/models/auth/check_activation_code_request_model.dart b/lib/models/auth/check_activation_code_request_model.dart index 856f1c43..9bb3d4f6 100644 --- a/lib/models/auth/check_activation_code_request_model.dart +++ b/lib/models/auth/check_activation_code_request_model.dart @@ -12,21 +12,22 @@ class CheckActivationCodeRequestModel { String activationCode; String vidaAuthTokenID; String vidaRefreshTokenID; - + int oTPSendType; CheckActivationCodeRequestModel( {this.mobileNumber, - this.zipCode, - this.doctorID, - this.iPAdress, - this.channel, - this.languageID, - this.projectID, - this.versionID, - this.generalid, - this.logInTokenID, - this.activationCode, - this.vidaAuthTokenID, - this.vidaRefreshTokenID}); + this.zipCode, + this.doctorID, + this.iPAdress, + this.channel, + this.languageID, + this.projectID, + this.versionID, + this.generalid, + this.logInTokenID, + this.activationCode, + this.vidaAuthTokenID, + this.vidaRefreshTokenID, + this.oTPSendType}); CheckActivationCodeRequestModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -42,6 +43,7 @@ class CheckActivationCodeRequestModel { activationCode = json['activationCode']; vidaAuthTokenID = json['VidaAuthTokenID']; vidaRefreshTokenID = json['VidaRefreshTokenID']; + oTPSendType = json['OTP_SendType']; } Map toJson() { @@ -59,6 +61,7 @@ class CheckActivationCodeRequestModel { data['activationCode'] = this.activationCode; data['VidaAuthTokenID'] = this.vidaAuthTokenID; data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; + data['OTP_SendType'] = this.oTPSendType; return data; } } diff --git a/lib/screens/auth/login_screen.dart b/lib/screens/auth/login_screen.dart index 5b495abb..1ed441e4 100644 --- a/lib/screens/auth/login_screen.dart +++ b/lib/screens/auth/login_screen.dart @@ -1,7 +1,17 @@ import 'dart:async'; +import 'dart:io'; import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../lookups/auth_lookup.dart'; @@ -23,21 +33,48 @@ class _LoginsreenState extends State { Future _prefs = SharedPreferences.getInstance(); String platformImei; - Future platformImeiFuture; - - bool _isLoading = false; - - Future getSharedPref() async { - sharedPref.getString('platformImei').then((imei) { - platformImei = imei; - }); - } - + // Future platformImeiFuture; + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); + bool _isLoading = true; + ProjectViewModel projectViewModel; + AuthService authService = AuthService(); @override void initState() { super.initState(); - platformImeiFuture = _prefs.then((SharedPreferences prefs) { - return (prefs.getString('platformImei')); + + _firebaseMessaging.setAutoInitEnabled(true); + if (Platform.isIOS) { + _firebaseMessaging.requestNotificationPermissions(); + } + + _firebaseMessaging.getToken().then((String token) async { + if (DEVICE_TOKEN == "" && projectViewModel.isLogin == false) { + DEVICE_TOKEN = token; + changeLoadingStata(true); + authService.selectDeviceImei(DEVICE_TOKEN).then((value) { + print(authService.dashboardItemsList); + + if (authService.dashboardItemsList.length > 0) { + sharedPref.setObj( + LAST_LOGIN_USER, authService.dashboardItemsList[0]); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: null, + ))); + } else { + changeLoadingStata(false); + } + //changeLoadingStata(false); + }); + } else { + changeLoadingStata(false); + } + + // else if (projectViewModel.isLogin) { + // getNotificationCount(token); + // } + }).catchError((err) { + print(err); }); } @@ -56,54 +93,46 @@ class _LoginsreenState extends State { @override Widget build(BuildContext context) { - getSharedPref(); - return AppScaffold( - isLoading: _isLoading, - isShowAppBar: false, - body: SafeArea( - child: ListView(children: [ - FutureBuilder( - future: platformImeiFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return DrAppCircularProgressIndeicator(); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Container( - margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), - alignment: Alignment.topLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (platformImei == null) - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.knownUser), - LoginForm( - changeLoadingStata: - changeLoadingStata, - ), - ], - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.unknownUser), - KnownUserLogin(), - ], + projectViewModel = Provider.of(context); + + return BaseView( + onModelReady: (model) => {}, + builder: (_, model, w) => AppScaffold( + baseViewModel: model, + isShowAppBar: false, + body: SafeArea( + child: (_isLoading == false) + ? ListView(children: [ + Container( + margin: + EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), + alignment: Alignment.topLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AuthHeader(loginType.knownUser), + LoginForm( + changeLoadingStata: changeLoadingStata, ), - ])); - } - } - }), - ]), - ), - ); + ], + ) + + // : Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // AuthHeader(loginType.unknownUser), + // KnownUserLogin(), + // ], + // ), + ])) + ]) + : Center(child: CircularProgressIndicator()), + ), + )); } } diff --git a/lib/screens/auth/verification_methods_screen.dart b/lib/screens/auth/verification_methods_screen.dart index 2b411dc0..0045f032 100644 --- a/lib/screens/auth/verification_methods_screen.dart +++ b/lib/screens/auth/verification_methods_screen.dart @@ -42,7 +42,7 @@ class _VerificationMethodsScreenState extends State { Widget build(BuildContext context) { return AppScaffold( isLoading: _isLoading, - isShowAppBar: false, + isShowAppBar: false, body: ListView(children: [ Container( margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 0), diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 20f22382..adc912d6 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -1,3 +1,4 @@ +import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; @@ -58,6 +59,14 @@ class _DashboardScreenState extends State { if (_isInit) { projectsProvider = Provider.of(context); projectsProvider.getDoctorClinicsList(); + + if (DEVICE_TOKEN != '') { + var request = await sharedPref.getObj(DOCTOR_PROFILE); + authProvider.insertDeviceImei(request).then((value) { + print(value['ReturnValue']); + changeIsLoading(false); + }); + } } _isInit = false; } diff --git a/lib/screens/reschedule-leaves/reschedule_leave.dart b/lib/screens/reschedule-leaves/reschedule_leave.dart index 6f3299d1..5d546c04 100644 --- a/lib/screens/reschedule-leaves/reschedule_leave.dart +++ b/lib/screens/reschedule-leaves/reschedule_leave.dart @@ -792,7 +792,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, @@ -846,7 +846,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, diff --git a/lib/util/helpers.dart b/lib/util/helpers.dart index 9a398949..a7229ca2 100644 --- a/lib/util/helpers.dart +++ b/lib/util/helpers.dart @@ -346,15 +346,17 @@ class Helpers { } logout() async { + DEVICE_TOKEN = ""; String lang = await sharedPref.getString(APP_Language); await clearSharedPref(); sharedPref.setString(APP_Language, lang); Navigator.of(AppGlobal.CONTEX).pushReplacementNamed(LOGIN); + // TODO Fix it // Navigator.of(AppGlobal.CONTEX).popUntil((ModalRoute.withName(LOGIN))); } - String parseHtmlString(String htmlString) { + String parseHtmlString(String htmlString) { final document = parse(htmlString); final String parsedString = parse(document.body.text).documentElement.text; @@ -380,11 +382,11 @@ class Helpers { hintText: selectedText != null ? selectedText : hintText, suffixIcon: isDropDown ? suffixIcon != null - ? suffixIcon - : Icon( - Icons.arrow_drop_down, - color: dropDownColor != null ? dropDownColor : Colors.black, - ) + ? suffixIcon + : Icon( + Icons.arrow_drop_down, + color: dropDownColor != null ? dropDownColor : Colors.black, + ) : null, hintStyle: TextStyle( fontSize: 14, @@ -394,7 +396,8 @@ class Helpers { } static BoxDecoration containerBorderDecoration( - Color containerColor, Color borderColor, {double borderWidth = -1}) { + Color containerColor, Color borderColor, + {double borderWidth = -1}) { return BoxDecoration( color: containerColor, shape: BoxShape.rectangle, diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index b167b48e..600b5f33 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -544,15 +544,60 @@ class TranslationBase { localizedValues['referralEmptyMsg'][locale.languageCode]; String get referralSuccessMsg => localizedValues['referralSuccessMsg'][locale.languageCode]; - String get diagnoseType => localizedValues['diagnoseType'][locale.languageCode]; + String get diagnoseType => + localizedValues['diagnoseType'][locale.languageCode]; String get condition => localizedValues['condition'][locale.languageCode]; String get id => localizedValues['id'][locale.languageCode]; String get quantity => localizedValues['quantity'][locale.languageCode]; String get codeNo => localizedValues['codeNo'][locale.languageCode]; String get covered => localizedValues['covered'][locale.languageCode]; - String get approvalRequired => localizedValues['approvalRequired'][locale.languageCode]; - String get uncoveredByDoctor => localizedValues['uncoveredByDoctor'][locale.languageCode]; - String get chiefComplaintEmptyMsg => localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + String get approvalRequired => + localizedValues['approvalRequired'][locale.languageCode]; + String get uncoveredByDoctor => + localizedValues['uncoveredByDoctor'][locale.languageCode]; + String get chiefComplaintEmptyMsg => + localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + + String get moreVerification => + localizedValues['more-verify'][locale.languageCode]; + + String get welcomeBack => + localizedValues['welcome-back'][locale.languageCode]; + + String get accountInfo => + localizedValues['account-info'][locale.languageCode]; + + String get useAnotherAccount => + localizedValues['another-acc'][locale.languageCode]; + + String get verifyLoginWith => + localizedValues['verify-login-with'][locale.languageCode]; + + String get register => localizedValues['register-user'][locale.languageCode]; + + String get verifyFingerprint => + localizedValues['verify-with-fingerprint'][locale.languageCode]; + + String get verifyFaceID => + localizedValues['verify-with-faceid'][locale.languageCode]; + + String get verifySMS => + localizedValues['verify-with-sms'][locale.languageCode]; + + String get verifyWhatsApp => + localizedValues['verify-with-whatsapp'][locale.languageCode]; + + String get lastLoginAt => localizedValues['last-login'][locale.languageCode]; + + String get lastLoginWith => + localizedValues['last-login-with'][locale.languageCode]; + + String get verifyFingerprint2 => + localizedValues['verify-fingerprint'][locale.languageCode]; + String get verificationMessage => + localizedValues['verification_message'][locale.languageCode]; + String get validationMessage => + localizedValues['validation_message'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/auth/known_user_login.dart b/lib/widgets/auth/known_user_login.dart index 4df37d66..b181aed8 100644 --- a/lib/widgets/auth/known_user_login.dart +++ b/lib/widgets/auth/known_user_login.dart @@ -70,8 +70,8 @@ class _KnownUserLoginState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); - var imeiModel = {'IMEI': _platformImei}; - _loginTypeFuture = authProv.selectDeviceImei(imeiModel); + // var imeiModel = {'IMEI': _platformImei}; + // _loginTypeFuture = authProv.selectDeviceImei(imeiModel); return FutureBuilder( future: Future.wait([_loggedUserFuture, _loginTypeFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { diff --git a/lib/widgets/auth/login_form.dart b/lib/widgets/auth/login_form.dart index 808b1763..3aac5cdd 100644 --- a/lib/widgets/auth/login_form.dart +++ b/lib/widgets/auth/login_form.dart @@ -224,26 +224,29 @@ class _LoginFormState extends State { } login(context, AuthViewModel authProv, Function changeLoadingStata) { - FocusScopeNode currentFocus = FocusScope.of(context); - changeLoadingStata(true); + showLoading(); if (loginFormKey.currentState.validate()) { loginFormKey.currentState.save(); sharedPref.setInt(PROJECT_ID, userInfo.projectID); authProv.login(userInfo).then((res) { - changeLoadingStata(false); - + //changeLoadingStata(false); + hideLoading(); if (res['MessageStatus'] == 1) { // insertDeviceImei(res, authProv); saveObjToString(LOGGED_IN_USER, res); + sharedPref.remove(LAST_LOGIN_USER); sharedPref.setString(TOKEN, res['LogInTokenID']); print("token" + res['LogInTokenID']); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); } else { // handel error helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { - print('$err'); + hideLoading(); changeLoadingStata(false); helpers.showErrorToast(err); }); @@ -273,7 +276,11 @@ class _LoginFormState extends State { if (res['MessageStatus'] == 1) { setSharedPref('platformImei', _platformImei); saveObjToString(LOGGED_IN_USER, preRes); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); // save imei on shared preferance } else { @@ -350,4 +357,18 @@ class _LoginFormState extends State { primaryFocus.unfocus(); } + + showLoading() { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + } + + hideLoading() { + Navigator.pop(context); + } } diff --git a/lib/widgets/auth/verification_methods.dart b/lib/widgets/auth/verification_methods.dart index 32c541a3..0de81fdf 100644 --- a/lib/widgets/auth/verification_methods.dart +++ b/lib/widgets/auth/verification_methods.dart @@ -1,11 +1,22 @@ import 'dart:io' show Platform; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; -import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; +import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; +import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; +import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/otp/sms-popup.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_button.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; import 'package:flutter/material.dart'; -import 'package:hexcolor/hexcolor.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import '../../config/size_config.dart'; @@ -40,6 +51,17 @@ class _VerificationMethodsState extends State { Future _loggedUserFuture; var _loggedUser; var verificationMethod; + GetIMEIDetailsModel user; + final LocalAuthentication auth = LocalAuthentication(); + var _availableBiometrics; + ProjectViewModel projectsProvider; + var isMoreOption = false; + var onlySMSBox = false; + static BuildContext _context; + var loginTokenID; + + bool authenticated; + @override void initState() { super.initState(); @@ -50,6 +72,13 @@ class _VerificationMethodsState extends State { sharedPref.getObj(LOGGED_IN_USER).then((userInfo) { _loggedUser = userInfo; }); + sharedPref.getObj(LAST_LOGIN_USER).then((lastLogin) { + if (lastLogin != null) { + user = GetIMEIDetailsModel.fromJson(lastLogin); + } + }); + + print(user); } @override @@ -63,6 +92,7 @@ class _VerificationMethodsState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); + projectsProvider = Provider.of(context); return FutureBuilder( future: Future.wait([_loggedUserFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -75,66 +105,205 @@ class _VerificationMethodsState extends State { return Text('Error: ${snapshot.error}'); } else { return Container( - width: SizeConfig.realScreenWidth * 0.80, + width: SizeConfig.realScreenWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - hideSilentMethods() - ? TranslationBase.of(context).firstStep - : TranslationBase.of(context).pleaseChoose, - style: TextStyle( - fontSize: 3.5 * SizeConfig.textMultiplier, - ), - ), - SizedBox( - height: 20, - ), Container( - height: SizeConfig.realScreenHeight * 0.6, - child: CustomScrollView( - primary: false, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(0), - sliver: SliverGrid.count( - // childAspectRatio: 0.7, - crossAxisSpacing: 0, - mainAxisSpacing: 5, - crossAxisCount: 2, - children: [ - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFingerprintMethod( - context, authProv), - replacement: - buildWhatsAppMethod(context, authProv), - ), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFaceIDMethod(context, authProv), - replacement: - buildSMSMethod(context, authProv), - ), - Visibility( - visible: - hideSilentMethods() ? false : true, - child: buildWhatsAppMethod( - context, authProv)), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildSMSMethod(context, authProv), - ), - ], - ), - ), - ], - ), - // height: 500, - ), - SizedBox( - // height: 20, - ) + height: SizeConfig.realScreenHeight * 0.6, + child: Column( + children: [ + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context) + .welcomeBack + + ' ' + + user.doctorName, + fontSize: + SizeConfig.textMultiplier * 3.5, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .accountInfo, + fontSize: + SizeConfig.textMultiplier * 2.5, + ), + SizedBox( + height: 20, + ), + Card( + color: Colors.grey[300], + child: Row( + children: [ + Flexible( + child: ListTile( + title: Text( + TranslationBase.of(context) + .lastLoginAt, + textAlign: TextAlign.center, + overflow: + TextOverflow.ellipsis, + ), + subtitle: Text( + // user. != null + // ? formatDate(Helpers + // .convertStringToDate( + // user + // .)) + // : user != + // null + // ? formatDate(Helpers + // .convertStringToDate(user + // .createdOn)) + //: + '--', + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )), + Flexible( + child: ListTile( + title: Text( + TranslationBase.of( + context) + .lastLoginWith, + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + subtitle: Text( + getType(user.logInTypeID, + context), + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )) + ], + )), + ], + ) + : Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + this.onlySMSBox == false + ? AppText( + TranslationBase.of(context) + .verifyLoginWith, + fontSize: SizeConfig + .textMultiplier * + 3.5, + textAlign: TextAlign.left, + ) + : AppText( + TranslationBase.of(context) + .verifyFingerprint2, + fontSize: SizeConfig + .textMultiplier * + 2.5, + textAlign: TextAlign.start, + ), + ]), + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: InkWell( + onTap: () => { + authenticateUser( + 3, + BiometricType + .face + .index, + authProv) + }, + child: getButton( + user.logInTypeID, + authProv))), + Expanded( + child: + getButton(5, authProv)) + ]) + ]) + : Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + onlySMSBox == false + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: getButton( + 3, authProv)), + Expanded( + child: getButton( + 2, authProv)) + ], + ) + : SizedBox(), + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: + getButton(1, authProv)), + Expanded( + child: getButton(4, authProv)) + ], + ), + ]), + Expanded( + flex: 1, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + user != null + ? Row( + children: [ + Expanded( + child: Button( + title: + TranslationBase.of(context) + .useAnotherAccount, + onTap: () { + Navigator.of(context) + .pushNamed(LOGIN); + }, + )), + ], + ) + : SizedBox(), + ], + ), + ) + ], + )) ], ), ); @@ -143,119 +312,6 @@ class _VerificationMethodsState extends State { }); } - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: buildSMSMethod Methods widget - */ - Center buildSMSMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_sms_icon.png', - TranslationBase.of(context).sms, () { - sendActivationCodeByOtpNotificationType(1, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build WhatsApp Methods widget - */ - Center buildWhatsAppMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_whatsapp_icon.png', - TranslationBase.of(context).whatsApp, () { - sendActivationCodeByOtpNotificationType(2, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build FaceID Methods widget - */ - Center buildFaceIDMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_faceid_icon.png', - TranslationBase.of(context).faceId, () { - sendActivationCodeByOtpNotificationType(3, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Fingerprint Methods widget - */ - Center buildFingerprintMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_fingerprint_icon.png', - TranslationBase.of(context).fingerprint, () { - sendActivationCodeByOtpNotificationType(4, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Verification Methods widget - */ - Center buildVerificationMethod(context, url, dec, Function fun) { - return Center( - child: InkWell( - onTap: fun, - child: Container( - // height: SizeConfig.heightMultiplier *2, - height: SizeConfig.heightMultiplier * 19, - width: SizeConfig.widthMultiplier * 37, - - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - width: 1, - color: HexColor( - '#CCCCCC') // <--- border width here - ), - borderRadius: BorderRadius.all(Radius.circular(10))), - child: Column( - children: [ - Container( - margin: EdgeInsetsDirectional.only( - top: SizeConfig.heightMultiplier * 0.5), - child: Image.asset( - url, - height: SizeConfig.heightMultiplier * 10, - fit: BoxFit.cover, - ), - ), - SizedBox( - height: 10, - ), - Text( - dec, - style: TextStyle(fontSize: SizeConfig.textMultiplier * 2), - ) - ], - ), - ), - ), - ); - } - bool hideSilentMethods() { return verificationMethod == 4 || verificationMethod == 3 ? true : false; } @@ -267,64 +323,473 @@ class _VerificationMethodsState extends State { *@return: *@desc: send Activation Code By Otp Notification Type */ - sendActivationCodeByOtpNotificationType(oTPSendType, AuthViewModel authProv) async { + sendActivationCodeByOtpNotificationType( + oTPSendType, AuthViewModel authProv) async { // TODO : build enum for verfication method if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(true); int projectID = await sharedPref.getInt(PROJECT_ID); ActivationCodeModel activationCodeModel = ActivationCodeModel( + // facilityId: projectID != null ? projectID : 15, //user.projectID, + // generalid: "Cs2020@2016\$2958", + // memberID: _loggedUser != null + // ? _loggedUser['List_MemberInformation'][0]['MemberID'] + // : user.doctorID, + // zipCode: _loggedUser != null + // ? _loggedUser['ZipCode'] + // : user.outSA == true + // ? '966' + // : '971', + // mobileNumber: + // _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, facilityId: projectID, generalid: "Cs2020@2016\$2958", memberID: _loggedUser['List_MemberInformation'][0]['MemberID'], zipCode: _loggedUser['ZipCode'], mobileNumber: _loggedUser['MobileNumber'], - + otpSendType: oTPSendType.toString(), password: widget.password); - Map model = { - - "OTP_SendType": oTPSendType - }; - try { authProv .sendActivationCodeForDoctorApp(activationCodeModel) .then((res) { - widget.changeLoadingStata(false); - - if (res['MessageStatus'] == 1) { - print("VerificationCode : "+ res["VerificationCode"]); - sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); - sharedPref.setString(VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); - sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); - Navigator.of(context).pushReplacementNamed(VERIFY_ACCOUNT, - arguments: {'model': model}); - } else { - print(res['ErrorEndUserMessage']); - helpers.showErrorToast(res['ErrorEndUserMessage']); - } - }) - .catchError((err) { + widget.changeLoadingStata(false); + + if (res['MessageStatus'] == 1) { + print("VerificationCode : " + res["VerificationCode"]); + sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); + sharedPref.setString( + VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); + sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); + this.startSMSService(oTPSendType, authProv); + } else { + print(res['ErrorEndUserMessage']); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { print('$err'); widget.changeLoadingStata(false); helpers.showErrorToast(); }); } catch (e) {} - - } else { // TODO route to this page with parameters to inicate we should present 2 option if (Platform.isAndroid && oTPSendType == 3) { helpers.showErrorToast('Your device not support this feature'); } else { - Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext context) => - VerificationMethodsScreen(password: widget.password,))); + // Navigator.of(context).push(MaterialPageRoute( + // builder: (BuildContext context) => + // VerificationMethodsScreen(password: widget.password,))); // Navigator.of(context).pushNamed(VERIFICATION_METHODS, // arguments: {'verificationMethod': oTPSendType}); } } } + + Widget getButton(flag, authProv) { + switch (flag) { + case 2: + return InkWell( + onTap: () => {authenticateUser(2, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(30, 15, 30, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/104.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyWhatsApp, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 1: + return InkWell( + onTap: () => {authenticateUser(1, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/103.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 20, + ) + : SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifySMS, + fontSize: projectsProvider.isArabic + ? SizeConfig.textMultiplier * 1.8 + : SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 3: + return InkWell( + onTap: () => { + authenticateUser(3, BiometricType.fingerprint.index, authProv) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/102.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFingerprint, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 4: + return InkWell( + onTap: () => + {authenticateUser(4, BiometricType.face.index, authProv)}, + child: RoundedContainer( + backgroundColor: checkIfBiometricAvailable(BiometricType.face) + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/101.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFaceID, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + + default: + return InkWell( + onTap: () => { + setState(() { + isMoreOption = true; + }) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 0, 5, 5), + child: Column( + children: [ + Image.asset( + 'assets/images/login/more_icon.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 15, + ) + : SizedBox( + height: 10, + ), + AppText( + TranslationBase.of(context).moreVerification, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + } + } + + getType(type, context) { + switch (type) { + case 1: + return TranslationBase.of(context).verifySMS; + break; + case 3: + return TranslationBase.of(context).verifyFingerprint; + break; + case 4: + return TranslationBase.of(context).verifyFaceID; + break; + case 2: + return TranslationBase.of(context).verifyWhatsApp; + break; + default: + return TranslationBase.of(context).verifySMS; + break; + } + } + + bool checkIfBiometricAvailable(BiometricType biometricType) { + bool isAvailable = false; + if (_availableBiometrics != null) { + for (var i = 0; i < _availableBiometrics.length; i++) { + if (biometricType == _availableBiometrics[i]) isAvailable = true; + } + } + return isAvailable; + } + + formatDate(date) { + return DateFormat('MMM dd, yyy, kk:mm').format(date); + } + + authenticateUser(type, isActive, authProv) { + //GifLoaderDialogUtils.showMyDialog(context); + // if (type == 2 || type == 3) { + // fingrePrintBefore = type; + // } + //this.selectedOption = fingrePrintBefore != null ? fingrePrintBefore : type; + + switch (type) { + case 1: + this.loginWithSMS(1, isActive, authProv); + break; + case 2: + this.loginWithSMS(2, isActive, authProv); + + break; + case 3: + this.loginWithFingurePrintFace(3, isActive, authProv); + break; + case 4: + this.loginWithFingurePrintFace(4, isActive, authProv); + break; + default: + break; + } + // sharedPref.setInt(LAST_LOGIN, + // this.selectedOption); //this.cs.sharedService.setStorage(this.selectedOption, AuthenticationService.LAST_LOGIN); + } + + loginWithSMS(type, isActive, authProv) { + this.sendActivationCode(type, authProv); + // //if (!el.disabled) { + // if (this.user != null) { + // this.checkUserAuthentication(type); + // } else { + // // if (this.loginTokenID != null) { + // this.sendActivationCode(type, authProv); + // // } else { + // //this.checkUserAuthentication(type); + // // } + // } + } + + // checkUserAuthentication(type) { + // // showLoader(true); + // // var req = getCommonRequest(type: type); + // // req.logInTokenID = ""; + + // // var request = CheckPatientAuthenticationReq.fromJson(req.toJson()); + + // // sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); + // // authService + // // .checkPatientAuthentication(request) + // // .then((value) => { + // // GifLoaderDialogUtils.hideDialog(context), + // // if (value['isSMSSent']) + // // { + // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']), + // // this.loginTokenID = value['LogInTokenID'], + // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // // // Future.delayed(Duration(seconds: 1), () { + // // this.sendActivationCode(type) + // // // }) + // // } + // // else + // // { + // // if (value['IsAuthenticated']) {this.checkActivationCode()} + // // } + // // }) + // // .catchError((err) { + // // print(err); + // // GifLoaderDialogUtils.hideDialog(context); + // // }); + // } + Future _getAvailableBiometrics() async { + var availableBiometrics; + try { + availableBiometrics = await auth.getAvailableBiometrics(); + } on PlatformException catch (e) { + print(e); + } + if (!mounted) return; + + setState(() { + _availableBiometrics = availableBiometrics; + }); + } + + sendActivationCode(type, authProv) async { + sendActivationCodeByOtpNotificationType(type, authProv); + } + + startSMSService(type, authProv) { + sharedPref.setInt(OTP_TYPE, type); + new SMSOTP( + context, + type, + _loggedUser['MobileNumber'], + (value) { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + + this.checkActivationCode(authProv, value: value); + }, + () => { + Navigator.pop(context), + print('Faild..'), + }, + ).displayDialog(context); + } + + loginWithFingurePrintFace(type, isActive, authProv) async { + if (isActive == 1) { + // this.startBiometricLoginIfAvailable(); + authenticated = await auth.authenticateWithBiometrics( + localizedReason: 'Scan your fingerprint to authenticate', + useErrorDialogs: true, + stickyAuth: true); + if (user.logInTypeID == 1 || user.logInTypeID == 2) { + this.onlySMSBox = true; + } else { + this.checkActivationCode(authProv); + } + + // if (authenticated == true) { + // if (user != null && (user.logInTypeID == 4 || user.logInTypeID == 3)) { + // //this.checkActivationCode(); + // } else { + // // var request = this.getCommonRequest(type: type); + // // this.getMobileInfo(request); + // } + // } + } + } + + checkActivationCode(AuthViewModel authProv, {value}) async { + CheckActivationCodeRequestModel checkActivationCodeForDoctorApp = + new CheckActivationCodeRequestModel( + zipCode: _loggedUser['ZipCode'], + mobileNumber: _loggedUser['MobileNumber'], + projectID: await sharedPref.getInt(PROJECT_ID), + logInTokenID: await sharedPref.getString(LOGIN_TOKEN_ID), + activationCode: value, + oTPSendType: await sharedPref.getInt(OTP_TYPE), + generalid: "Cs2020@2016\$2958"); + + authProv + .checkActivationCodeForDoctorApp(checkActivationCodeForDoctorApp) + .then((res) async { + widget.changeLoadingStata(false); + if (res['MessageStatus'] == 1) { + sharedPref.setString(TOKEN, res['AuthenticationTokenID']); + if (res['List_DoctorProfile'] != null) { + loginProcessCompleted(res['List_DoctorProfile'][0], authProv); + } else { + ClinicModel clinic = + ClinicModel.fromJson(res['List_DoctorsClinic'][0]); + getDocProfiles(clinic, authProv); + } + } else { + //changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + //changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } + + loginProcessCompleted(Map profile, authProv) { + var doctor = DoctorProfileModel.fromJson(profile); + authProv.setDoctorProfile(doctor); + sharedPref.setObj(DOCTOR_PROFILE, profile); + projectsProvider.isLogin = true; + Navigator.of(context).pushReplacementNamed(HOME); + } + + getDocProfiles(ClinicModel clinicInfo, authProv) { + ProfileReqModel docInfo = new ProfileReqModel( + doctorID: clinicInfo.doctorID, + clinicID: clinicInfo.clinicID, + license: true, + projectID: clinicInfo.projectID, + tokenID: '', + languageID: 2); + authProv.getDocProfiles(docInfo.toJson()).then((res) { + if (res['MessageStatus'] == 1) { + loginProcessCompleted(res['DoctorProfileList'][0], authProv); + } else { + // changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + // changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } } diff --git a/lib/widgets/otp/sms-popup.dart b/lib/widgets/otp/sms-popup.dart new file mode 100644 index 00000000..dfcb33cd --- /dev/null +++ b/lib/widgets/otp/sms-popup.dart @@ -0,0 +1,346 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'dart:math'; + +import 'package:provider/provider.dart'; + +class SMSOTP { + final type; + final mobileNo; + final Function onSuccess; + final Function onFailure; + final context; + + int remainingTime = 600; + + Future timer; + + static BuildContext _context; + + static bool _loading; + + SMSOTP( + this.context, + this.type, + this.mobileNo, + this.onSuccess, + this.onFailure, + ); + + final verifyAccountForm = GlobalKey(); + + TextEditingController digit1 = TextEditingController(text: ""); + TextEditingController digit2 = TextEditingController(text: ""); + TextEditingController digit3 = TextEditingController(text: ""); + TextEditingController digit4 = TextEditingController(text: ""); + + Map verifyAccountFormValue = { + 'digit1': '', + 'digit2': '', + 'digit3': '', + 'digit4': '', + }; + final focusD1 = FocusNode(); + final focusD2 = FocusNode(); + final focusD3 = FocusNode(); + final focusD4 = FocusNode(); + String errorMsg; + ProjectViewModel projectProvider; + String displayTime = ''; + + displayDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (context) { + projectProvider = Provider.of(context); + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + this.onFailure(); + }, + ) + ], + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0))), + content: StatefulBuilder(builder: (context, setState) { + if (displayTime == '') { + startTimer(setState); + } + return Container( + color: Colors.white, + height: SizeConfig.realScreenHeight * 0.5, + width: SizeConfig.realScreenWidth * 0.8, + child: Center( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + type == 1 + ? Image.asset('assets/images/login/103.png') + : Image.asset('assets/images/login/104.png'), + Padding( + padding: EdgeInsets.only(top: 5), + child: AppText( + TranslationBase.of(context).verificationMessage + + ' XXXXXX' + + mobileNo + .toString() + .substring(mobileNo.toString().length - 3), + textAlign: TextAlign.center, + )), + Form( + key: verifyAccountForm, + child: Padding( + padding: EdgeInsets.only(top: 20), + child: Directionality( + textDirection: TextDirection.ltr, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + textInputAction: TextInputAction.next, + style: buildTextStyle(), + autofocus: true, + maxLength: 1, + controller: digit1, + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + validator: validateCodeDigit, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD2); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD2); + verifyAccountFormValue['digit1'] = + val.trim(); + checkValue(); + } + }, + ), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD2, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit2, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD3); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD3); + verifyAccountFormValue['digit2'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD3, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit3, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD4); + verifyAccountFormValue['digit3'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD4, + maxLength: 1, + textAlign: TextAlign.center, + style: buildTextStyle(), + controller: digit4, + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + verifyAccountFormValue['digit4'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + ], + )), + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: AppText( + TranslationBase.of(context).validationMessage + + ' ' + + displayTime, + color: Colors.red, + textAlign: TextAlign.center, + )) + ], + ))), + ); + }), + ); + }); + } + + TextStyle buildTextStyle() { + return TextStyle( + fontSize: SizeConfig.textMultiplier * 3, + ); + } + + InputDecoration buildInputDecoration(BuildContext context) { + return InputDecoration( + counterText: " ", + // ts/images/password_icon.png + // contentPadding: EdgeInsets.only(top: 20, bottom: 20), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + ); + } + + String validateCodeDigit(value) { + if (value.isEmpty) { + return ' '; + } else if (value.length == 3) { + print(value); + } else { + return null; + } + } + + checkValue() { + //print(verifyAccountFormValue); + if (verifyAccountForm.currentState.validate()) { + onSuccess(digit1.text.toString() + + digit2.text.toString() + + digit3.text.toString() + + digit4.text.toString()); + } + } + + getSecondsAsDigitalClock(int inputSeconds) { + var sec_num = + int.parse(inputSeconds.toString()); // don't forget the second param + var hours = (sec_num / 3600).floor(); + var minutes = ((sec_num - hours * 3600) / 60).floor(); + var seconds = sec_num - hours * 3600 - minutes * 60; + var minutesString = ""; + var secondsString = ""; + minutesString = + minutes < 10 ? "0" + minutes.toString() : minutes.toString(); + secondsString = + seconds < 10 ? "0" + seconds.toString() : seconds.toString(); + return minutesString + ":" + secondsString; + } + + startTimer(setState) { + this.remainingTime--; + setState(() { + displayTime = this.getSecondsAsDigitalClock(this.remainingTime); + }); + + timer = Future.delayed(Duration(seconds: 1), () { + if (this.remainingTime > 0) { + startTimer(setState); + } else { + Navigator.pop(context); + } + }); + } + + static void showLoadingDialog(BuildContext context, bool _loading) async { + _context = context; + + if (_loading == false) { + Navigator.of(context).pop(); + return; + } + _loading = true; + await showDialog( + context: _context, + barrierDismissible: false, + builder: (BuildContext context) { + return SimpleDialog( + elevation: 0.0, + backgroundColor: Colors.transparent, + children: [ + Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.black), + ), + ) + ], + ); + }); + } + + static void hideSMSBox(context) { + Navigator.pop(context); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7f1d8c1d..4d8e049b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -316,6 +316,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.2.1" + firebase_core: + dependency: transitive + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.3" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1+1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.3" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 57ed4cbb..e0e4ce33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: #Dependency Injection get_it: ^4.0.2 + #firebase + firebase_messaging: ^7.0.0 #Autocomplete TextField autocomplete_textfield: ^1.7.3 @@ -93,7 +95,7 @@ flutter: assets: - assets/images/ - assets/images/dashboard/ - + - assets/images/login/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.